ARTEMIS-2838 - migrate to HawtIO 2

https://issues.apache.org/jira/browse/ARTEMIS-2838
This commit is contained in:
Andy Taylor 2020-02-17 10:20:19 +00:00
parent 5be917ff06
commit 0ce173dcb5
102 changed files with 5561 additions and 6090 deletions

View File

@ -30,6 +30,8 @@ import org.apache.activemq.artemis.cli.factory.BrokerFactory;
import org.apache.activemq.artemis.cli.factory.jmx.ManagementFactory;
import org.apache.activemq.artemis.cli.factory.security.SecurityManagerFactory;
import org.apache.activemq.artemis.components.ExternalComponent;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.management.ManagementContext;
import org.apache.activemq.artemis.dto.BrokerDTO;
import org.apache.activemq.artemis.dto.ComponentDTO;
@ -81,7 +83,33 @@ public class Run extends LockAbstract {
ActiveMQSecurityManager security = SecurityManagerFactory.create(broker.security);
server = BrokerFactory.createServer(broker.server, security);
ActivateCallback activateCallback = new ActivateCallback() {
@Override
public void preActivate() {
try {
managementContext.start();
} catch (Exception e) {
ActiveMQServerLogger.LOGGER.unableStartManagementContext(e);
return;
}
try {
server.getServer().getManagementService().registerHawtioSecurity(managementContext.getArtemisMBeanServerGuard());
} catch (Exception e) {
ActiveMQServerLogger.LOGGER.unableToDeployHawtioMBean(e);
}
}
@Override
public void deActivate() {
try {
server.getServer().getManagementService().unregisterHawtioSecurity();
} catch (Exception e) {
//ok to ignore
}
}
};
server = BrokerFactory.createServer(broker.server, security, activateCallback);
managementContext.start();
server.createComponents();

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.net.URI;
import org.apache.activemq.artemis.cli.ConfigurationException;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.dto.BrokerDTO;
import org.apache.activemq.artemis.dto.ServerDTO;
import org.apache.activemq.artemis.integration.Broker;
@ -53,7 +54,7 @@ public class BrokerFactory {
return createBrokerConfiguration(new URI(configuration), artemisHome, artemisInstance, artemisURIInstance);
}
public static Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security) throws Exception {
public static Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback) throws Exception {
if (brokerDTO.configuration != null) {
BrokerHandler handler;
URI configURI = brokerDTO.getConfigurationURI();
@ -65,7 +66,7 @@ public class BrokerFactory {
throw new ConfigurationException("Invalid configuration URI, can't find configuration scheme: " + configURI.getScheme());
}
return handler.createServer(brokerDTO, security);
return handler.createServer(brokerDTO, security, activateCallback);
}
return null;
}

View File

@ -16,11 +16,12 @@
*/
package org.apache.activemq.artemis.cli.factory;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.dto.ServerDTO;
import org.apache.activemq.artemis.integration.Broker;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
public interface BrokerHandler {
Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security);
Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback);
}

View File

@ -16,6 +16,7 @@
*/
package org.apache.activemq.artemis.cli.factory;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.dto.ServerDTO;
import org.apache.activemq.artemis.integration.Broker;
import org.apache.activemq.artemis.integration.FileBroker;
@ -24,7 +25,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
public class FileBrokerHandler implements BrokerHandler {
@Override
public Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security) {
return new FileBroker(brokerDTO, security);
public Broker createServer(ServerDTO brokerDTO, ActiveMQSecurityManager security, ActivateCallback activateCallback) {
return new FileBroker(brokerDTO, security, activateCallback);
}
}

View File

@ -23,6 +23,7 @@ import java.util.Map;
import org.apache.activemq.artemis.core.config.FileDeploymentManager;
import org.apache.activemq.artemis.core.config.impl.FileConfiguration;
import org.apache.activemq.artemis.core.config.impl.LegacyJMSConfiguration;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ServiceComponent;
@ -33,6 +34,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
public class FileBroker implements Broker {
private final String configurationUrl;
private ActivateCallback activateCallback;
private boolean started;
@ -40,9 +42,10 @@ public class FileBroker implements Broker {
private Map<String, ActiveMQComponent> components;
public FileBroker(ServerDTO broker, ActiveMQSecurityManager security) {
public FileBroker(ServerDTO broker, ActiveMQSecurityManager security, ActivateCallback activateCallback) {
this.securityManager = security;
this.configurationUrl = broker.configuration;
this.activateCallback = activateCallback;
}
@Override
@ -116,7 +119,7 @@ public class FileBroker implements Broker {
createDirectories(configuration);
components = fileDeploymentManager.buildService(securityManager, ManagementFactory.getPlatformMBeanServer());
components = fileDeploymentManager.buildService(securityManager, ManagementFactory.getPlatformMBeanServer(), activateCallback);
}
/*

View File

@ -50,7 +50,7 @@ public class FileBrokerTest {
serverDTO.configuration = "broker-nojms.xml";
FileBroker broker = null;
try {
broker = new FileBroker(serverDTO, new ActiveMQJAASSecurityManager());
broker = new FileBroker(serverDTO, new ActiveMQJAASSecurityManager(), null);
broker.start();
JMSServerManagerImpl jmsServerManager = (JMSServerManagerImpl) broker.getComponents().get("jms");
Assert.assertNull(jmsServerManager);
@ -70,8 +70,8 @@ public class FileBrokerTest {
ServerDTO serverDTO2 = new ServerDTO();
serverDTO1.configuration = "FileBrokerTest-broker1.xml";
serverDTO2.configuration = "FileBrokerTest-broker2.xml";
FileBroker broker1 = new FileBroker(serverDTO1, new ActiveMQJAASSecurityManager());
FileBroker broker2 = new FileBroker(serverDTO2, new ActiveMQJAASSecurityManager());
FileBroker broker1 = new FileBroker(serverDTO1, new ActiveMQJAASSecurityManager(), null);
FileBroker broker2 = new FileBroker(serverDTO2, new ActiveMQJAASSecurityManager(), null);
try {
broker1.start();
Assert.assertTrue(broker1.isStarted());
@ -115,7 +115,7 @@ public class FileBrokerTest {
securityConfiguration.addUser("myUser", "myPass");
securityConfiguration.addRole("myUser", "guest");
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), securityConfiguration);
broker = new FileBroker(serverDTO, securityManager);
broker = new FileBroker(serverDTO, securityManager, null);
broker.start();
ActiveMQServerImpl activeMQServer = (ActiveMQServerImpl) broker.getComponents().get("core");
Assert.assertNotNull(activeMQServer);

View File

@ -460,6 +460,9 @@ public interface ActiveMQServerControl {
@Attribute(desc = ADDRESS_MEMORY_USAGE_PERCENTAGE_DESCRIPTION)
int getAddressMemoryUsagePercentage();
@Attribute(desc = "Returns the HA Policy of this broker as a String")
String getHAPolicy();
/**
* Returns the runtime size of the authentication cache
*/

View File

@ -160,4 +160,8 @@ public final class ObjectNameBuilder {
return "";
}
}
public ObjectName getManagementContextObjectName() throws Exception {
return ObjectName.getInstance(String.format("hawtio:type=security,area=jmx,name=ArtemisJMXSecurity"));
}
}

View File

@ -627,6 +627,11 @@ public interface QueueControl {
CompositeData[] browse(@Parameter(name = "page", desc = "Current page") int page,
@Parameter(name = "pageSize", desc = "Page size") int pageSize) throws Exception;
@Operation(desc = "Browse Messages", impact = MBeanOperationInfo.ACTION)
CompositeData[] browse(@Parameter(name = "page", desc = "Current page") int page,
@Parameter(name = "pageSize", desc = "Page size") int pageSize,
@Parameter(name = "filter", desc = "filter") String filter) throws Exception;
/**
* Resets the MessagesAdded property
*/

View File

@ -28,6 +28,8 @@ import org.apache.activemq.artemis.api.core.SimpleString;
public final class ResourceNames {
public static final String BROKER = "broker";
public static final String MANAGEMENT_SECURITY = "managementsecurity";
public static final String QUEUE = "queue.";
public static final String ADDRESS = "address.";

View File

@ -153,6 +153,9 @@
<map from="${basedir}/src/main/webapp/" to="" />
</pathconvert>
<echo>Files: ${plugin-scripts}</echo>
<!--<replace file="${webapp-outdir}/plugin/js/brandingPlugin.js">
<replacefilter token="@artemis.version@" value="${project.version}"/>
</replace>-->
</target>
<!-- this exports plugin-scripts to the maven build, without
@ -254,6 +257,16 @@
<exclude>log4j.properties</exclude>
</excludes>
</resource>
<resource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.*</include>
</includes>
<excludes>
<exclude>log4j.properties</exclude>
</excludes>
</resource>
</webResources>
</configuration>
</plugin>

View File

@ -17,15 +17,208 @@
/* fonts */
@import url("../../../console/app/themes/fonts/Open-Sans/stylesheet.css");
@import url("../../../console/app/themes/fonts/Droid-Sans-Mono/stylesheet.css");
/* You can customise the styles of your application here. */
@font-face {
font-family: 'PatternFlyIcons-webfont';
src: url('../../../console/fonts/PatternFlyIcons-webfont.eot');
url('../../../console/fonts/PatternFlyIcons-webfont.woff') format('woff'),
url('../../../console/fonts/PatternFlyIcons-webfont.ttf') format('truetype'),
url('../../../console/fonts/PatternFlyIcons-webfont.svg') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'OpenSans';
src: url('../../../console/fonts/OpenSans-Regular-webfont.eot');
url('../../../console/fonts/OpenSans-Regular-webfont.woff') format('woff'),
url('../../../console/fonts/OpenSans-Regular-webfont.ttf') format('truetype'),
url('../../../console/fonts/OpenSans-Regular-webfont.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/*Uses ActiveMQ colors in broker diagram*/
svg text {
font-family: PatternFlyIcons-webfont;
}
.pf-topology-svg g.ThisBroker circle {
stroke: #801944;
fill: #c12766;
}
.pf-topology-svg g.MasterBroker circle {
stroke: #801944;
fill: #c12766;
}
.pf-topology-svg g.SlaveBroker circle {
stroke: #82171b;
fill: #cf242a;
}
.pf-topology-svg g.Address circle {
stroke: #2b326e;
fill: #3e489f;
}
.pf-topology-svg g.Queue circle {
stroke: #50621d;
fill: #78932c;
}
/*Adds a border to top of page*/
.pf-c-page__header {
border-top: 3px solid #B21054;
}
/* Change the background image for Login page and About modal as well as text color etc*/
.pf-c-login, .pf-c-about-modal-box__hero {
background-image: url("/activemq-branding/plugin/img/login-screen-background.png");
background-size: cover;
--pf-c-form__label--Color: white;
}
.pf-c-login__main {
grid-area: main;
background-color: transparent;
}
.pf-c-login__footer .pf-c-list a {
color: white;
}
.pf-c-login__footer p {
font-size: 150%;
}
.pf-c-login__main-body label {
color: white;
}
.pf-c-login__main-header {
color: white;
}
/*These change the color of the buttons*/
.btn-link {
color: #B24E78;
}
.pf-c-button.pf-m-primary {
background-color: #B24E78;
}
.pf-c-button.pf-m-primary.pf-m-hover, .pf-c-button.pf-m-primary:hover {
background-color: #B24E78;
background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
background: #B21054;
border-color: #B24E78;
}
.pf-c-title.pf-m-3xl {
color: white;
}
.btn-primary {
background-color: #B24E78;
background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
background-repeat: repeat-x;
border-color: #B24E78;
color: #fff;
}
.btn-primary.active.focus,
.btn-primary.active:focus,
.btn-primary.active:hover, .btn-primary:active.focus,
.btn-primary:active:focus,
.btn-primary:active:hover,
.open .dropdown-toggle.btn-primary.focus,
.open .dropdown-toggle.btn-primary:focus,
.open .dropdown-toggle.btn-primary:hover {
background-color: #B24E78;
border-color: #B21054;
}
/*These change the row ina table when hovered over*/
.table-hover>tbody>tr:hover {
background-color: #B24E78;
}
.table-hover>tbody>tr:hover td {
background-color: #B24E78;
}
select>option:hover,
select>option:active {
background: #B24E78;
background-color: #B24E78;
}
tbody>tr:hover {
background-color: #B24E78;
}
/*This controls the color of the buttons when clicked, hovered or visited*/
.btn-primary:hover,
.btn-primary.hover
.btn-primary:active,
.btn-primary.active,
.btn-primary:focus,
.btn-primary.focus,
.btn-primary:visited,
.btn-primary.visited{
background-color: #B24E78;
background-image: linear-gradient(to bottom,#B24E78 0,#B24E78 100%);
background: #B21054;
border-color: #B24E78;
}
/*This changes the color of the hover item in the JMX Tree*/
.treeview-pf-hover .list-group-item:hover {
background-color: #B24E78!important;
border-color: #B24E78!important;
}
/*This changes the color of the chosen selection in the JMX Tree*/
.treeview-pf-select .list-group-item.node-selected {
background: #B24E78!important;
border-color: #B24E78!important;
color: #fff!important;
}
/* This changes the color of the underline in the main left menuLeft hand menu tab underline*/
.pf-c-nav__list .pf-m-current.pf-c-nav__link::after, .pf-c-nav__list .pf-m-current>.pf-c-nav__link::after {
background-color: #B24E78;
}
.pf-c-nav__list .pf-c-nav__link.pf-m-hover::after, .pf-c-nav__list .pf-c-nav__link:hover::after {
background-color: #B24E78;
}
.card-pf.card-pf-accented {
border-top-color: #B24E78;
}
/*This changes the hover color in all the tables*/
.table-hover tbody tr:hover td.focus {
background-color: #B24E78;
}
/*This changes the color of the sort column header*/
table.dataTable thead .sorting_asc, table.dataTable thead .sorting_desc {
color: #B24E78!important;
position: relative;
}
/*This is the original css from HawtIO 1,leaving as is as somemay be used*/
* {
font-family: OpenSans;
font-family: "Open Sans";
}
body {
font-family: OpenSans;
font-family: "Open Sans";
}
#log-panel-statements li {
@ -750,25 +943,6 @@ td.adding {
border-bottom-left-radius: 0px;
}
.login-wrapper {
background-color: rgba(255, 168, 27, 0.3);
box-shadow: rgba(255, 168, 27, 0.2) 0 0 30px 10px;
}
.login-wrapper form {
background-color: rgba(255, 255, 255, 0.2);
box-shadow: inset rgba(255, 168, 27, 0.2) 0 0 30px 10px;
}
.login-form form fieldset .control-group label {
color: white;
font-weight: bolder;
}
.login-logo {
color: white;
}
/** highlight required fields which have no focus */
input.ng-invalid,
textarea.ng-invalid,
@ -1171,7 +1345,7 @@ i.expandable-indicator.folder {
tr.selected,
tr.selected .ngCell,
tr.selected .ngCellText a,
tr.selected .ngCellText i,
.table-striped tbody tr.selected:nth-child(odd) td {
background-color: #c9dde1;
}
@ -1421,6 +1595,21 @@ h1, h2, h3, h4, h5, h6 {
font-family: "Overpass", sans-serif;
}
.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover {
color: #B21054;
cursor: default;
background-color: #fff;
border: 1px solid #ddd;
border-bottom-color: transparent;
}
table.jmx-attributes-table td {
color: #B21054;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
a {
color: #B21054;
text-decoration: none;
@ -1802,89 +1991,6 @@ select, textarea, input[type="text"], input[type="password"], input[type="dateti
*/
}
div[ng-controller='Core.LoginController']:after {
position: relative;
horiz-align: center;
}
.login-wrapper {
top: inherit;
border-radius: 0;
box-shadow: none;
left: 0;
position: absolute;
bottom: 15%;
padding-left: 0;
width: 100%;
min-width: 850px;
border-top: 1px rgba(255, 255, 255, 0.05) solid;
border-bottom: 1px rgba(255, 255, 255, 0.05) solid;
background-color: rgba(255, 255, 255, 0.1);
}
.login-logo>img {
height: 150px;
}
.login-logo {
top: -200px;
/* with no app title */
/* left: 183px; */
left: 45px;
width: 700px;
}
.login-logo span {
position: relative;
top: 2px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.login-wrapper form {
background: inherit;
border-radius: 0;
box-shadow: none;
padding: 0;
margin: 0;
}
.login-wrapper form fieldset {
padding-top: 40px;
padding-bottom: 40px;
width: 344px;
}
.login-wrapper form fieldset input[type="text"],
.login-wrapper form fieldset input[type="password"] {
margin: 4px;
padding: 3px 6px;
min-width: 200px;
height: 26px;
border: 1px #b6b6b6 solid;
border-radius: 2px;
background: url("../img/input-background.png") repeat-x top left;
}
.login-wrapper form fieldset input[type="text"]:hover,
.login-wrapper form fieldset input[type="password"]:hover {
border-color: #B2577A;
}
.login-wrapper form fieldset input[type="text"]:focus,
.login-wrapper form fieldset input[type="password"]:focus {
border-color: #B2577A;
box-shadow: #B2577A 0 0 5px;
}
.login-wrapper form fieldset .control-group .controls .checkbox {
position: absolute;
top: 185px;
left: 181px;
}
.dropdown-menu li > a:hover,
.dropdown-menu li > a:focus,
.dropdown-submenu:hover > a {
@ -1915,62 +2021,6 @@ div[ng-controller='Core.LoginController']:after {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#B26182', endColorstr='#B2577A', GradientType=0);
}
.login-wrapper form fieldset button[type="submit"] {
position: relative;
left: 39px;
padding: 4px 14px;
border: 1px #B24E78 solid;
border-radius: 2px;
background-image: linear-gradient(top, #B26182 0%, #B2577A 100%);
background-image: -o-linear-gradient(top, #B26182 0%, #B2577A 100%);
background-image: -moz-linear-gradient(top, #B26182 0%, #B2577A 100%);
background-image: -webkit-linear-gradient(top, #B26182 0%, #B2577A 100%);
background-image: -ms-linear-gradient(top, #B26182 0%, #B2577A 100%);
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, #B26182),
color-stop(1,0, #B2577A)
);
color: #fff;
font-weight: bold;
font-size: 12px;
letter-spacing: 0.6px;
}
.login-wrapper form fieldset button[type="submit"]:hover,
.login-wrapper form fieldset button[type="submit"]:focus {
background-color: #B26182;
background-image: none;
cursor: pointer;
}
.login-wrapper form fieldset button[type="submit"]:active {
background-color: #B27497;
background-image: none;
cursor: pointer;
box-shadow: inset 0 0 5px 3px #B2577A;
}
.login-wrapper form fieldset input[type="checkbox"] {
margin-right: 6px;
}
.login-wrapper form fieldset input[type="text"],
.login-wrapper form fieldset input[type="password"] {
color: #ffffff;
background-color: inherit;
margin: 4px 0px;
margin-bottom: 14px;
width: 282px;
}
.login-wrapper form fieldset button[type="submit"] {
float: right;
margin-top: 12px;
}
.logbar {
width: 100%;
left: 0;
@ -2155,7 +2205,7 @@ li.dropdown.open > a.dropdown-toggle {
border-bottom: 1px solid #d4d4d4;
}
.ngRow.selected .ngCellText a {
.ngRow.selected .ngCellText i {
color: #ffffff !important;
background-color: #B21054 !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,93 @@
/*
* 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.
*/
/**
* The main entry point for the Branding module
*/
var Branding = (function (Branding) {
/**
* The name of this plugin
*/
Branding.pluginName = 'activemq-branding';
/**
* This plugin's logger instance
*/
Branding.log = Logger.get('activemq-branding-plugin');
/**
* The top level path of this plugin on the server
*/
Branding.contextPath = '/activemq-branding';
/**
* This plugin's AngularJS module instance.
*/
Branding.module = angular.module(Branding.pluginName, [])
.run(initPlugin);
/**
* Here you can overwrite hawtconfig.json by putting the JSON
* data directly to configManager.config property.
*/
function initPlugin(configManager, aboutService) {
configManager.config = {
"branding": {
"appName": "Artemis Console",
"appLogoUrl": `${Branding.contextPath}/plugin/img/activemq.png`,
"companyLogoUrl": `${Branding.contextPath}/plugin/img/activemq.png`,
"css": `${Branding.contextPath}/plugin/css/activemq.css`,
"favicon": `${Branding.contextPath}/plugin/img/favicon.png`
},
"login": {
"description": "ActiveMQ Artemis Management Console",
"links": [
{
"url": "/user-manual/index.html",
"text": "User Manual"
},
{
"url": "https://activemq.apache.org/",
"text": "Website"
}
]
},
"about": {
"title": "ActiveMQ Artemis Management Console",
"productInfo": [],
"additionalInfo": "",
"imgSrc": `${Branding.contextPath}/plugin/img/activemq.png`
},
"disabledRoutes": []
};
aboutService.addProductInfo('Artemis', '${project.version}');
// Calling this function is required to apply the custom css and
// favicon settings
Core.applyBranding(configManager);
Branding.log.info(Branding.pluginName, "loaded");
}
initPlugin.$inject = ['configManager', 'aboutService'];
return Branding;
})(Branding || {});
// tell the Hawtio plugin loader about our plugin so it can be
// bootstrapped with the rest of AngularJS
hawtioPluginLoader.addModule(Branding.pluginName);

View File

@ -1,97 +0,0 @@
/*
* 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.
*/
/**
* The activemq hawtio theme
*
* @module activemqBranding
* @main activemq
*/
var localStorage = Core.getLocalStorage();
localStorage['showWelcomePage'] = false;
var activemqBranding = (function (self) {
self.log = Logger.get("activemq");
self.context = '../activemq-branding/';
self.pluginName = 'hawtio-activemq-branding';
hawtioPluginLoader.registerPreBootstrapTask(function (task) {
Themes.definitions['activemq'] = {
label: 'activemq',
file: self.context + 'plugin/css/activemq.css',
loginBg: self.context + 'plugin/img/login-screen-background.png'
};
if (!('theme' in localStorage)) {
localStorage['theme'] = 'activemq';
}
localStorage['showWelcomePage'] = false;
Themes.brandings['activemq'] = {
label: 'activemq',
setFunc: function(branding) {
branding.appName = 'ActiveMQ Management Console';
branding.appLogo = self.context + 'plugin/img/activemq.png';
branding.logoOnly = true;
branding.fullscreenLogin = true;
branding.css = self.context + 'plugin/css/branding.css';
branding.favicon = self.context + 'plugin/img/favicon.png';
branding.welcomePageUrl = self.context + 'plugin/doc/welcome.md';
return branding;
}
}
if (!('branding' in localStorage)) {
localStorage['branding'] = 'activemq';
}
task();
});
self.module = angular.module(self.pluginName, ['hawtioCore']);
self.module.run(function (branding) {
self.log.info("ActiveMQ theme loaded");
if (localStorage['theme'] != 'activemq' || localStorage['branding'] != 'activemq') {
localStorage['theme'] = 'activemq';
localStorage['branding'] = 'activemq';
location.reload();
}
/**
* By default tabs are pulled from the "container" perspective, here
* we can define includes or excludes to customize the available tabs
* in hawtio. Use "href" to match from the start of a URL and "rhref"
* to match a URL via regex string.
*
* Currently we need to exclude provided diagnostics,
* as it exposes proprietary Oracle JVM feature, flight recorder.
*
*/
window['Perspective']['metadata'] = {
container: {
label: "Container",
lastPage: "#/help",
topLevelTabs: {
excludes: [
{
href: "#/diagnostics"
}
]
}
}
};
});
return self;
})(activemqBranding || {});
hawtioPluginLoader.addModule(activemqBranding.pluginName);

View File

@ -45,7 +45,7 @@
<dependency>
<groupId>io.hawt</groupId>
<artifactId>hawtio-web</artifactId>
<artifactId>hawtio-war</artifactId>
<version>${hawtio.version}</version>
<!--
NOTE this WAR dependency type which enables this WAR to
@ -61,12 +61,12 @@
<version>${hawtio.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<!--<dependency>
<groupId>io.hawt</groupId>
<artifactId>hawtio-git</artifactId>
<version>${hawtio.version}</version>
<scope>provided</scope>
</dependency>
</dependency>-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -97,7 +97,7 @@
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/*.md</include>
<include>**/*.svg</include>
<!-- include any other file types you want to filter -->
</includes>
</resource>
@ -105,54 +105,12 @@
<overlays>
<overlay>
<groupId>io.hawt</groupId>
<artifactId>hawtio-web</artifactId>
<artifactId>hawtio-war</artifactId>
<excludes>
<exclude>bower_components/bootstrap/docs/build/**/*</exclude>
<exclude>bower_components/bootstrap/docs/examples/**/*</exclude>
<exclude>bower_components/bootstrap/docs/templates/**/*</exclude>
<exclude>bower_components/bootstrap/docs/assets/img/examples/**/*</exclude>
<exclude>bower_components/bootstrap/docs/assets/img/example-sites/**/*</exclude>
<exclude>bower_components/bootstrap/js/tests/**/*</exclude>
<exclude>bower_components/bootstrap/docs/**/*.html</exclude>
<exclude>bower_components/Font-Awesome/src/**/*</exclude>
<exclude>bower_components/d3/src/**/*</exclude>
<exclude>bower_components/d3/test/**/*</exclude>
<exclude>bower_components/elastic.js/src/**/*</exclude>
<exclude>bower_components/elastic.js/tests/**/*</exclude>
<exclude>bower_components/elastic.js/examples/**/*</exclude>
<exclude>bower_components/jquery/src/**/*</exclude>
<exclude>bower_components/jquery/test/**/*</exclude>
<exclude>bower_components/js-logger/src/**/*</exclude>
<excluse>WEB-INF/lib/guava*.jar</excluse>
<excluse>WEB-INF/lib/slf4j-api*.jar</excluse>
<excluse>lib/camelModel.js</excluse>
<exclude>app/activemq/**/*</exclude>
<exclude>app/api/**/*</exclude>
<exclude>app/apm/**/*</exclude>
<exclude>app/camel/**/*</exclude>
<exclude>app/camin/**/*</exclude>
<exclude>app/datatable/**/*</exclude>
<exclude>app/dozer/**/*</exclude>
<exclude>app/elasticsearch/**/*</exclude>
<exclude>app/fabric/**/*</exclude>
<exclude>app/fabric-deploy/**/*</exclude>
<exclude>app/fabric-requirements/**/*</exclude>
<exclude>app/forcegraph/**/*</exclude>
<exclude>app/git/**/*</exclude>
<exclude>app/health/**/*</exclude>
<exclude>app/ide/**/*</exclude>
<exclude>app/infinispan/**/*</exclude>
<exclude>app/jboss/**/*</exclude>
<exclude>app/jclouds/**/*</exclude>
<exclude>app/junit/**/*</exclude>
<exclude>app/maven/**/*</exclude>
<exclude>app/openejb/**/*</exclude>
<exclude>app/quartz/**/*</exclude>
<exclude>app/site/**/*</exclude>
<exclude>app/springbatch/**/*</exclude>
<exclude>app/springBoot/**/*</exclude>
<exclude>app/tomcat/**/*</exclude>
<exclude>app/wiki-drop/**/*</exclude>
<exclude>hawtconfig.json</exclude>
<exclude>img/icons/**/*</exclude>
<exclude>img/**/*</exclude>
<exclude>fonts/glyphicons**</exclude>
</excludes>
</overlay>
</overlays>

View File

@ -1,53 +0,0 @@
<h3 class="about-header">About Apache ActiveMQ Artemis</h3>
<div id="content">
<div class="wrapper">
<p>Apache ActiveMQ Artemis is an open source project to build a multi-protocol, embeddable, very high performance, clustered, asynchronous messaging system.</p>
<p>Apache ActiveMQ Artemis has a proven non blocking architecture. It delivers outstanding performance. </p>
<p>A full guide on features and usage can be found in the <a href="#/help">User Manual</a></p>
<p/>{{branding.appName}} is powered by <img class='no-shadow' ng-src='img/logo-16px.png'><a href="http://hawt.io/">hawtio</a><p/>
<h2 id = "Features">Features</h2>
<ul>
<li>AMQP protocol support</li>
<li>OpenWire support for ActiveMQ 5 clients</li>
<li>MQTT support</li>
<li>STOMP protocol support</li>
<li>HornetQ Core protocol support for HornetQ 2.4,2.5 clients</li>
<li>JMS 2.0 and 1.1 support</li>
<li>High availability with shared store and non shared store (replication)</li>
<li>Flexible Clustering</li>
<li>High performance journal for message persistence</li>
<li>Queue memory limitation</li>
<li>SSL support</li>
<li>Management over JMX, JMS and core protocol</li>
<li>Large message support</li>
<li>Topic hierarchies</li>
<li>Producer flow control</li>
<li>Consumer flow control</li>
<li>Diverts</li>
<li>Last value queue</li>
<li>Message Groups</li>
<li>OSGi support</li>
</ul>
<h2 id = "Links">Links</h2>
<ul>
<li><a target="_blank" href="#/help">User Manual</a></li>
<li><a href="https://activemq.apache.org/artemis/download.html">Download</a></li>
<li><a href="https://activemq.apache.org/artemis/migration.html">Migration</a></li>
<li><a href="https://activemq.apache.org/artemis/community.html">Community</a></li>
</ul>
</div>
</div>
<h4>Versions</h4>
**artemis** version: ${project.version}
**hawtio** version: {{hawtioVersion}}
**jolokia** version: {{jolokiaVersion}}
<div ng-show="serverVendor">
<strong>server</strong> version: {{serverVendor}} {{serverProduct}} {{serverVersion}}
</div>

View File

@ -1,104 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="JVM.ConnectController">
<div class="row-fluid connect-column-container" hawtio-auto-columns=".connect-column">
<div class="connect-column">
<div class="alert alert-info">
<p>
This page allows you to connect to remote processes which <strong>already have a <a
href="http://jolokia.org/">jolokia agent</a> running inside them</strong>. You will need to know the
host name, port and path of the jolokia agent to be able to connect.
</p>
<p>
If the process you wish to connect to does not have a jolokia agent inside, please refer to the <a
href="http://jolokia.org/agent.html">jolokia documentation</a> for how to add a JVM, servlet or OSGi
based agent inside it.
</p>
<p ng-show="hasLocalMBean()">
Use the <strong><a href="#/jvm/local">Local Tab</a></strong> to connect to processes locally on this machine (which will install a jolokia agent automatically if required).
</p>
<p ng-show="!hasLocalMBean()">
The <strong>Local Tab</strong> is not currently enabled because either the server side <strong>hawtio-local-jvm-mbean plugin</strong> is not installed or this
JVM cannot find the <strong>com.sun.tools.attach.VirtualMachine</strong> API usually found in the <strong>tool.jar</strong>.
Please see the <a href="http://hawt.io/faq/index.html">FAQ entry</a> for more details.
</p>
</div>
</div>
<div class="connect-column">
<dl>
<dt>Saved Connections</dt>
<dd>
<form class="form-horizontal no-bottom-margin">
<fieldset>
<div class="control-group">
<label class="control-label">Connections: </label>
<div class="controls">
<select ng-model="lastConnection"
ng-options="value.name as key for (key, value) in connectionConfigs">
<option value=""
ng-hide="lastConnection">New connection...</option>
</select>
<button class="btn btn-success"
title="Connect to this server"
ng-disabled="!lastConnection"
ng-click="gotoServer()"><i class="icon-share"></i></button>
<button class="btn btn-danger"
title="Delete this connection"
ng-disabled="!lastConnection"
ng-click="deleteConnection()"><i class="icon-remove-sign"></i></button>
<button class="btn btn-primary"
title="Create a new connection"
ng-disabled="!lastConnection"
ng-click="newConnection()"><i class="icon-plus"></i></button>
</div>
</div>
</fieldset>
</form>
</dd>
</dl>
<dl>
<dt>Connection Settings</dt>
<dd>
<div simple-form name="connectForm" data="formConfig" entity="currentConfig" onSubmit="gotoServer()"></div>
<div class="centered">
<button class="btn btn-primary"
ng-disabled="!forms.connectForm.$valid"
hawtio-submit="connectForm"
title="Saves the connection and opens a new browser window connecting to the given JVM process via its Jolokia servlet URL">Connect to remote server</button>
<button class="btn"
title="Save this configuration but don't open a new tab"
ng-disabled="!forms.connectForm.$valid"
ng-click="save()">Save</button>
</div>
</dd>
</dl>
</div>
</div>
</div>

View File

@ -0,0 +1,26 @@
{
"branding": {
"appName": "Artemis Console",
"appLogoUrl": "/activemq-branding/plugin/img/activemq.png",
"companyLogoUrl": "/activemq-branding/plugin/img/activemq.png",
"css": "/activemq-branding/plugin/css/activemq.css",
"favicon": "/activemq-branding/plugin/img/favicon.png"
},
"login": {
"description": "ActiveMQ Artemis Management Console",
"links": [
{
"url": "/user_manual/index.html",
"text": "User Manual"
}
]
},
"about": {
"title": "ActiveMQ Artemis Management Console",
"productInfo": [],
"additionalInfo": "",
"copyright": "",
"imgSrc": "/activemq-branding/plugin/img/activemq.png"
},
"disabledRoutes": []
}

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<svg enable-background="new 0 0 36 36" version="1.1" viewBox="0 0 36 36" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<style type="text/css">
/*stylelint-disable*/
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st1{filter:url(#b);}
.st2{mask:url(#a);}
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#BBBBBB;}
.st4{opacity:0.1;fill-rule:evenodd;clip-rule:evenodd;enable-background:new ;}
.st5{opacity:8.000000e-02;fill-rule:evenodd;clip-rule:evenodd;fill:#231F20;enable-background:new ;}
/*stylelint-enable*/
</style>
<circle class="st0" cx="18" cy="18.5" r="18"/>
<defs>
<filter id="b" x="5.2" y="7.2" width="25.6" height="53.6" filterUnits="userSpaceOnUse">
<feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/>
</filter>
</defs>
<mask id="a" x="5.2" y="7.2" width="25.6" height="53.6" maskUnits="userSpaceOnUse">
<g class="st1">
<circle class="st0" cx="18" cy="18.5" r="18"/>
</g>
</mask>
<g class="st2">
<g transform="translate(5.04 6.88)">
<path class="st3" d="m22.6 18.1c-1.1-1.4-2.3-2.2-3.5-2.6s-1.8-0.6-6.3-0.6-6.1 0.7-6.1 0.7 0 0 0 0c-1.2 0.4-2.4 1.2-3.4 2.6-2.3 2.8-3.2 12.3-3.2 14.8 0 3.2 0.4 12.3 0.6 15.4 0 0-0.4 5.5 4 5.5l-0.3-6.3-0.4-3.5 0.2-0.9c0.9 0.4 3.6 1.2 8.6 1.2 5.3 0 8-0.9 8.8-1.3l0.2 1-0.2 3.6-0.3 6.3c3 0.1 3.7-3 3.8-4.4s0.6-12.6 0.6-16.5c0.1-2.6-0.8-12.1-3.1-15z"/>
<path class="st4" d="m22.5 26c-0.1-2.1-1.5-2.8-4.8-2.8l2.2 9.6s1.8-1.7 3-1.8c0 0-0.4-4.6-0.4-5z"/>
<path class="st3" d="m12.7 13.2c-3.5 0-6.4-2.9-6.4-6.4s2.9-6.4 6.4-6.4 6.4 2.9 6.4 6.4-2.8 6.4-6.4 6.4z"/>
<path class="st5" d="m9.4 6.8c0-3 2.1-5.5 4.9-6.3-0.5-0.1-1-0.2-1.6-0.2-3.5 0-6.4 2.9-6.4 6.4s2.9 6.4 6.4 6.4c0.6 0 1.1-0.1 1.6-0.2-2.8-0.6-4.9-3.1-4.9-6.1z"/>
<path class="st4" d="m8.3 22.4c-2 0.4-2.9 1.4-3.1 3.5l-0.6 18.6s1.7 0.7 3.6 0.9l0.1-23z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -62,6 +62,10 @@
<schema-outdir>${basedir}/src/main/webapp/lib</schema-outdir>
<appjs-outfile>${webapp-outdir}/app/app.js</appjs-outfile>
<!--
<angular.version>1.7.9</angular.version>
-->
</properties>
<dependencies>

View File

@ -0,0 +1,27 @@
<!--
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.
Architecture
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Artemis plugin</title>
</head>
<body>
<h1>Hawtio :: Artemis plugin example</h1>
</body>
</html>

View File

@ -1,54 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.AddressesController">
<!-- TODO This should be templated and included -->
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
</div>
</div>

View File

@ -1,42 +0,0 @@
<!--
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.
Architecture
-->
<script type="text/ng-template" id="header">
<div class="tree-header" ng-controller="ARTEMIS.TreeHeaderController">
<div class="left">
</div>
<div class="right">
<i class="icon-chevron-down clickable"
title="Expand all nodes"
ng-click="expandAll()"></i>
<i class="icon-chevron-up clickable"
title="Unexpand all nodes"
ng-click="contractAll()"></i>
</div>
</div>
</script>
<hawtio-pane position="left" width="300" header="header">
<div id="tree-container"
ng-controller="Jmx.MBeansController">
<div id="artemistree"
ng-controller="ARTEMIS.TreeController"></div>
</div>
</hawtio-pane>
<div class="row-fluid">
<ng-include src="'app/jmx/html/subLevelTabs.html'"></ng-include>
<div id="properties" ng-view></div>
</div>

View File

@ -1,313 +0,0 @@
<!--
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.
Architecture
-->
<style type="text/css">
.span4.node-panel {
margin-top: 10px;
margin-left: 10px;
width: 33%;
}
.node-attributes dl {
margin-top: 5px;
margin-bottom: 10px;
}
.node-attributes dt {
width: 150px;
}
.node-attributes dd {
margin-left: 160px;
}
.node-attributes dd a {
/** lets make the destination links wrap */
-ms-word-break: break-all;
word-break: break-all;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto;
}
ul.viewMenu li {
padding-left: 10px;
padding-top: 2px;
padding-bottom: 2px;
}
div#pop-up {
display: none;
position: absolute;
color: white;
font-size: 14px;
background: rgba(0, 0, 0, 0.6);
padding: 5px 10px 5px 10px;
-moz-border-radius: 8px 8px;
border-radius: 8px 8px;
}
div#pop-up-title {
font-size: 15px;
margin-bottom: 4px;
font-weight: bolder;
}
div#pop-up-content {
font-size: 12px;
}
rect.graphbox {
fill: #FFF;
}
rect.graphbox.frame {
stroke: #222;
stroke-width: 2px
}
/* only things directly related to the network graph should be here */
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
marker.broker {
stroke: red;
fill: red;
stroke-width: 1.5px;
}
circle.broker {
fill: #0c0;
}
circle.brokerSlave {
fill: #c00;
}
circle.notActive {
fill: #c00;
}
path.link.group {
stroke: #ccc;
}
marker#group {
stroke: #ccc;
fill: #ccc;
}
circle.group {
fill: #eee;
stroke: #ccc;
}
circle.destination {
fill: #bbb;
stroke: #ccc;
}
circle.pinned {
stroke-width: 4.5px;
}
path.link.profile {
stroke-dasharray: 0, 2 1;
stroke: #888;
}
marker#container {
}
circle.container {
stroke-dasharray: 0, 2 1;
stroke: #888;
}
path.link.container {
stroke-dasharray: 0, 2 1;
stroke: #888;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
cursor: pointer;
}
circle.closeMode {
cursor: crosshair;
}
path.link.destination {
stroke: #ccc;
}
circle.topic {
fill: #c0c;
}
circle.queue {
fill: #00c;
}
circle.consumer {
fill: #cfc;
}
circle.producer {
fill: #ccf;
}
path.link.producer {
stroke: #ccc;
}
path.link.consumer {
stroke: #ccc;
}
path.link.network {
stroke: #ccc;
}
circle.selected {
stroke-width: 3px;
}
.selected {
stroke-width: 3px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}
</style>
<div class="row-fluid mq-page" ng-controller="ARTEMIS.BrokerDiagramController">
<div ng-hide="inDashboard" class="span12 page-padded">
<div class="section-header">
<div class="section-filter">
<input type="text" class="search-query" placeholder="Filter..." ng-model="searchFilter">
<i class="icon-remove clickable" title="Clear filter" ng-click="searchFilter = ''"></i>
</div>
<div class="section-controls">
<a href="#"
class="dropdown-toggle"
data-toggle="dropdown">
View &nbsp;<i class="icon-caret-down"></i>
</a>
<ul class="dropdown-menu viewMenu">
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.consumer"> Consumers
</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.producer"> Producers
</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.address"> Addresses
</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.queue"> Queues
</label>
</li>
<li class="divider"></li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.broker"> Brokers
</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.slave"> Slave brokers
</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.network"> Networks
</label>
</li>
<li class="divider"></li>
<li title="Should we show the details panel on the left">
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.panel"> Details panel
</label>
</li>
<li title="Show the summary popup as you hover over nodes">
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.popup"> Hover text
</label>
</li>
<li title="Show the labels next to nodes">
<label class="checkbox">
<input type="checkbox" ng-model="viewSettings.label"> Label
</label>
</li>
</ul>
</div>
</div>
</div>
<div id="pop-up">
<div id="pop-up-title"></div>
<div id="pop-up-content"></div>
</div>
<div class="row-fluid">
<div class="{{viewSettings.panel ? 'span8' : 'span12'}} canvas broker-canvas">
<div hawtio-force-graph graph="graph" selected-model="selectedNode" link-distance="150" charge="-600" nodesize="10" marker-kind="marker-end"
style="min-height: 800px">
</div>
</div>
<div ng-show="viewSettings.panel" class="span4 node-panel">
<div ng-show="selectedNode" class="node-attributes">
<dl ng-repeat="property in selectedNodeProperties" class="dl-horizontal">
<dt title="{{property.key}}">{{property.key}}:</dt>
<dd ng-bind-html-unsafe="property.value"></dd>
</dl>
</div>
</div>
</div>
<div ng-include="'app/fabric/html/connectToContainerDialog.html'"></div>
</div>

View File

@ -1,156 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.BrowseQueueController">
<div class="row-fluid">
<div class="span6">
<input class="search-query span12" type="text" ng-model="gridOptions.filterOptions.filterText"
placeholder="Filter messages">
</div>
<div class="span6">
<div class="pull-right">
<form class="form-inline">
<button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-show="dlq" ng-click="retryMessages()"
title="Moves the dead letter queue message back to its original destination so it can be retried" data-placement="bottom">
<i class="icon-reply"></i> Retry
</button>
<button class="btn" ng-disabled="gridOptions.selectedItems.length !== 1" ng-click="resendMessage()"
title="Edit the message to resend it" data-placement="bottom">
<i class="icon-share-alt"></i> Resend
</button>
<button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-click="moveDialog = true"
title="Move the selected messages to another destination" data-placement="bottom">
<i class="icon-share-alt"></i> Move
</button>
<button class="btn" ng-disabled="!gridOptions.selectedItems.length"
ng-click="deleteDialog = true"
title="Delete the selected messages">
<i class="icon-remove"></i> Delete
</button>
<button class="btn" ng-click="refresh()"
title="Refreshes the list of messages">
<i class="icon-refresh"></i>
</button>
</form>
</div>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions"></div>
</div>
<div hawtio-slideout="showMessageDetails" title="{{row.JMSMessageID}}">
<div class="dialog-body">
<div class="row-fluid">
<div class="pull-right">
<form class="form-horizontal no-bottom-margin">
<div class="btn-group"
hawtio-pager="messages"
on-index-change="selectRowIndex"
row-index="rowIndex"></div>
<button class="btn" ng-disabled="!gridOptions.selectedItems.length" ng-click="moveDialog = true"
title="Move the selected messages to another destination" data-placement="bottom">
<i class="icon-share-alt"></i> Move
</button>
<button class="btn btn-danger" ng-disabled="!gridOptions.selectedItems.length"
ng-click="deleteDialog = true"
title="Delete the selected messages">
<i class="icon-remove"></i> Delete
</button>
<button class="btn" ng-click="showMessageDetails = !showMessageDetails" title="Close this dialog">
<i class="icon-remove"></i> Close
</button>
</form>
</div>
</div>
<div class="row-fluid">
<div class="expandable closed">
<div title="Headers" class="title">
<i class="expandable-indicator"></i> Headers & Properties
</div>
<div class="expandable-body well">
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>Header</th>
<th>Value</th>
</tr>
</thead>
<tbody ng-bind-html-unsafe="row.headerHtml">
</tbody>
<!--
<tr ng-repeat="(key, value) in row.headers">
<td class="property-name">{{key}}</td>
<td class="property-value">{{value}}</td>
</tr>
-->
</table>
</div>
</div>
</div>
<div class="row-fluid">
<div>Displaying body as <span ng-bind="row.textMode"></span></div>
<div hawtio-editor="row.bodyText" read-only="true" mode='mode'></div>
</div>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Delete"
on-ok="deleteMessages()">
<div class="dialog-body">
<p>You are about to delete
<ng-pluralize count="gridOptions.selectedItems.length"
when="{'1': 'a message!', 'other': '{} messages!'}">
</ng-pluralize>
</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
<div hawtio-confirm-dialog="moveDialog"
ok-button-text="Move"
on-ok="moveMessages()">
<div class="dialog-body">
<p>Move
<ng-pluralize count="gridOptions.selectedItems.length"
when="{'1': 'message', 'other': '{} messages'}"></ng-pluralize>
to: <input type="text" ng-model="queueName" placeholder="Queue name"
typeahead="title.unescapeHTML() for title in queueNames($viewValue) | filter:$viewValue" typeahead-editable='true'></p>
<p>
You cannot undo this operation.<br>
Though after the move you can always move the
<ng-pluralize count="gridOptions.selectedItems.length"
when="{'1': 'message', 'other': 'messages'}"></ng-pluralize>
back again.
</p>
</div>
</div>
</div>

View File

@ -1,72 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.ConnectionsController">
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
<div class="pull-right">
<form class="form-inline">
<button class="btn-danger" ng-show="showClose"
ng-click="deleteDialog = true"
title="Close the selected Connection">
<i class="icon-remove"></i> Close
</button>
&nbsp;&nbsp;&nbsp;
</form>
</div>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Close"
on-ok="closeConnection()">
<div class="dialog-body">
<p>You are about to close the selected connection: {{gridOptions.selectedItems[0].connectionID}}
</p>
<p>Are you sure you want to continue.</p>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
</div>
</div>

View File

@ -1,75 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.ConsumersController">
<!-- TODO This should be templated and included -->
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
<div class="pull-right">
<form class="form-inline">
<button class="btn-danger" ng-show="showClose"
ng-click="deleteDialog = true"
title="Close the selected Consumer">
<i class="icon-remove"></i> Close
</button>
&nbsp;&nbsp;&nbsp;
</form>
</div>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Close"
on-ok="closeConsumer()">
<div class="dialog-body">
<p>You are about to close the selected consumer: {{gridOptions.selectedItems[0].id}}
</p>
<p>Are you sure you want to continue.</p>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
</div>
</div>

View File

@ -1,44 +0,0 @@
<!--
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.
Architecture
-->
<form class="form-horizontal" ng-controller="ARTEMIS.AddressController">
<div class="control-group">
<label class="control-label" for="addressName"
title="The routing name of this address">Address name</label>
<div class="controls">
<input id="addressName" type="text" maxlength="300" ng-model="addressName" placeholder="Address Name"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="routingType">Routing type</label>
<div class="controls">
<select id="routingType" ng-model="routingType">
<option value='0'>Multicast</option>
<option value='1'>Anycast</option>
<option value='2'>Both</option>
</select>
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-info" ng-click="createAddress(addressName, routingType)" ng-disabled="!addressName">Create Address</button>
</div>
</div>
</form>

View File

@ -1,77 +0,0 @@
<!--
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.
Architecture
-->
<form class="form-horizontal" ng-controller="ARTEMIS.QueueController">
<div class="control-group">
<label class="control-label" for="queueName"
title="The routing name of this address">Queue name</label>
<div class="controls">
<input id="queueName" type="text" maxlength="300" ng-model="queueName" placeholder="Queue Name"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="routingType">Routing type</label>
<div class="controls">
<select id="routingType" ng-model="routingType">
<option value='0'>Multicast</option>
<option value='1'>Anycast</option>
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="durable"
title="Whether the queue will be durable">Durable</label>
<div class="controls">
<input id="durable" type="checkbox" ng-model="durable" value="false">
</div>
</div>
<div class="control-group">
<label class="control-label" for="filter"
title="The user name to be used when connecting to the broker">Filter</label>
<div class="controls">
<input id="filter" type="text" maxlength="300" ng-model="filter" placeholder="Filter"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="maxConsumers"
title="The maximum consumers the queue can have">Max Consumers</label>
<div class="controls">
<input id="maxConsumers" type="number" ng-model="maxConsumers" placeholder="maxConsumers"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="purgeWhenNoConsumers"
title="Whether or not this queue should be purged (emptied and paused) when there are no consumers">Purge when no consumers</label>
<div class="controls">
<input id="purgeWhenNoConsumers" type="checkbox" ng-model="purgeWhenNoConsumers" value="false"/>
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-info" ng-click="createQueue(queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers)" ng-disabled="!queueName">Create Queue</button>
</div>
</div>
</form>

View File

@ -1,48 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.AddressController">
<div class="row-fluid">
<div class="control-group">
<div class="alert">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Warning:</strong> these operations cannot be undone. Please be careful!
</div>
</div>
</div>
<div class="row-fluid">
<div class="span4">
<div class="control-group">
<button type="submit" class="btn btn-warning" ng-click="deleteDialog = true">Delete address '{{name().unescapeHTML()}}'</button>
<label>This will remove the address completely.</label>
</div>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Delete"
on-ok="deleteAddress()">
<div class="dialog-body">
<p>You are about to delete the <b>{{name().unescapeHTML()}}</b> address</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
</div>

View File

@ -1,65 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.QueueController">
<div class="row-fluid">
<div class="control-group">
<div class="alert">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>Warning:</strong> these operations cannot be undone. Please be careful!
</div>
</div>
<h4>Queue '{{name().unescapeHTML()}}'</h4>
</div>
<div class="row-fluid">
<div class="control-group">
<hr>
<h5>Purge queue</h5>
<p>Purge all the current messages on the queue.</p>
<button type="submit" class="btn btn-warning" ng-click="purgeDialog = true">Purge queue</button>
</div>
</div>
<div class="row-fluid">
<div class="control-group">
<hr>
<h5>Delete queue</h5>
<p>Remove the queue completely.</p>
<button type="submit" class="btn btn-warning" ng-click="deleteDialog = true">Delete queue</button>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Delete"
on-ok="deleteDestination(true)">
<div class="dialog-body">
<p>You are about to delete the <b>{{name().unescapeHTML()}}</b> queue</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
<div hawtio-confirm-dialog="purgeDialog"
ok-button-text="Purge"
on-ok="purgeDestination()">
<div class="dialog-body">
<p>You are about to purge the <b>{{name().unescapeHTML()}}</b> queue</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
</div>

View File

@ -15,55 +15,60 @@
limitations under the License.
Architecture
-->
<div ng-controller="ARTEMIS.PreferencesController">
<form class="form-horizontal">
<form class="form-horizontal artemis-preferences-form" ng-controller="Artemis.PreferencesController">
<div class="control-group">
<label class="control-label" for="artemisUserName"
title="The user name to be used when connecting to the broker">User name</label>
<div class="controls">
<input id="artemisUserName" type="text" placeholder="username" ng-model="artemisUserName" autofill/>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisUserName">
Artemis user name
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
</label>
<div class="col-md-6">
<input id="artemisUserName" type="text" class="form-control" ng-model="artemisUserName"/>
</div>
<div class="control-group">
<label class="control-label" for="artemisPassword" title="Password to be used when connecting to the broker">Password</label>
</div>
<div class="controls">
<input id="artemisPassword" type="password" placeholder="password" ng-model="artemisPassword" autofill/>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisPassword">
Artemis password
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
</label>
<div class="col-md-6">
<input id="artemisPassword" type="password" class="form-control" ng-model="artemisPassword"/>
</div>
</div>
<div class="control-group">
<label class="control-label" for="artemisDLQ" title="The DLQ of the Broker">DLQ</label>
<div class="controls">
<input id="artemisDLQ" type="text" placeholder="DLQ" ng-model="artemisDLQ" autofill/>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisDLQ">
The DLQ of the Broker
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Dead Letter Queue of the Broker"></span>
</label>
<div class="col-md-6">
<input type="text" id="artemisDLQ" ng-model="artemisDLQ">
</div>
</div>
<div class="control-group">
<label class="control-label" for="artemisExpiryQueue" title="The Expiry Queue of the Broker">Expiry Queue</label>
<div class="controls">
<input id="artemisExpiryQueue" type="text" placeholder="ExpiryQueue" ng-model="artemisExpiryQueue" autofill/>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisExpiryQueue">
The Expiry of the Broker
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Expiry Queue of the Broker"></span>
</label>
<div class="col-md-6">
<input type="text" id="artemisExpiryQueue" ng-model="artemisExpiryQueue">
</div>
</div>
<div class="control-group">
<label class="control-label" for="byteMessages">Browse byte messages</label>
<div class="controls">
<select id="byteMessages" ng-model="activemqBrowseBytesMessages">
<option value='99'>Off</option>
<option value='8'>Decimal</option>
<option value='4'>Hex</option>
<option value='2'>Decimal and text</option>
<option value='1'>Hex and text</option>
</select>
<span class="help-block">Browsing byte messages should display the message body as</span>
</div>
<!-- <div class="form-group">
<label class="col-md-2 control-label" for="artemisBrowseBytesMessages">
Display message body as
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="Browsing byte messages should display the message body as"></span>
</label>
<div class="col-md-6">
<select id="artemisBrowseBytesMessages"
ng-model="artemisBrowseBytesMessages"
ng-options="key for (key, value) in messageBodyDisplayOptions"
ng-selected="artemisBrowseBytesMessages === value">
</select>
</div>
</div>-->
</form>
</div>
</form>

View File

@ -1,54 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.ProducersController">
<!-- TODO This should be templated and included -->
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
</div>
</div>

View File

@ -1,54 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.QueuesController">
<!-- TODO This should be templated and included -->
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns></div>
</div>
</div>

View File

@ -1,135 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.SendMessageController">
<div class="tabbable" ng-model="tab">
<div value="compose" class="tab-pane" title="Compose">
<!--
title="Compose a new message to send"
-->
<div class="row-fluid">
<span ng-show="noCredentials" class="alert">
No credentials set for endpoint! Please set your username and password in the <a
href="" ng-click="openPrefs()">Preferences</a> page
</span>
<form class="form-inline pull-right">
<div class="row-fluid">
<div class="controls">
<label class="control-label" for="durable" title="Is this message durable">Durable: </label>
<input id="durable" type="checkbox" ng-model="durable" value="true">
</div>
<button class="btn" ng-click="addHeader()" title="Add a new message header"><i
class="icon-plus"></i> Header
</button>
<button type="submit" class="btn btn-primary" ng-click="sendMessage(durable)">Send message</button>
</form>
</div>
<form class="form-inline bottom-margin" ng-submit="addHeader()">
<ol class="zebra-list header-list">
<div class="row-fluid">
<li ng-repeat="header in headers">
<div class="span4">
<input type="text" style="width: 100%" class="headerName"
ng-model="header.name"
typeahead="completion for completion in defaultHeaderNames() | filter:$viewValue"
typeahead-editable='true'
placeholder="Header name">
</div>
<div class="span6">
<input type="text" style="width: 100%" ng-model="header.value"
placeholder="Value of the message header">
</div>
<div class="span2">
<button type="submit" class="btn" title="Add a new message header">
<i class="icon-plus"></i>
</button>
<button type="button" ng-click="removeHeader(header)" class="btn" title="Removes this message header">
<i class="icon-remove"></i>
</button>
</div>
</li>
</div>
</ol>
</form>
<div class="row-fluid">
<form class="form-inline">
<div class="controls">
<label class="control-label" for="sourceFormat" title="The text format to use for the message payload">Payload
format: </label>
<select ng-model="codeMirrorOptions.mode.name" id="sourceFormat">
<option value="javascript">JSON</option>
<option value="text" selected>Plain text</option>
<option value="properties">Properties</option>
<option value="xml">XML</option>
</select>
<button class="btn" ng-click="autoFormat()"
title="Automatically pretty prints the message so its easier to read">Auto format
</button>
</div>
</form>
</div>
<div class="row-fluid">
<textarea ui-codemirror="codeMirrorOptions" ng-model="message"></textarea>
</div>
</div>
</tab>
<div ng-switch="showChoose">
<div ng-switch-when="true">
<div value="choose" class="tab-pane" title="Choose">
<!--
title="Choose messages to send from the available files in the Profile configuration for this container">
-->
<div class="row-fluid bottom-margin">
<span ng-show="noCredentials" class="alert">
No credentials set for endpoint! Please set your username and password in the <a
href="#/preferences">Preferences</a> page
</span>
<button type="submit" ng-disabled="!fileSelection().length" class="btn btn-primary pull-right"
ng-click="sendSelectedFiles()">
<ng-pluralize count="fileSelection().length"
when="{'0': 'No files selected', '1': 'Send the file','other': 'Send {} files'}">
</ng-pluralize>
</button>
</div>
<p>Choose which files to send from the profile configuration:</p>
<div class="control-group inline-block">
<input class="search-query" type="text" ng-model="searchText" placeholder="Filter..." autofocus>
</div>
<ul>
<li ng-repeat="fileName in profileFileNames | filter:searchText">
<input type="checkbox" ng-model="selectedFiles[fileName]"> {{fileName}}
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,74 +0,0 @@
<!--
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.
Architecture
-->
<div ng-controller="ARTEMIS.SessionsController">
<div class="row-fluid">
<div class="span24">
<div class="control-group inline-block">
<form class="form-inline no-bottom-margin">
&nbsp;<span class="label label-default">Filter</span>
&nbsp;&nbsp;
<select ng-model="filter.values.field" id="filter.values.field">
<option ng-repeat="option in filter.fieldOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<select ng-model="filter.values.operation" id="filter.values.operation">
<option ng-repeat="option in filter.operationOptions" value="{{option.id}}">{{option.name}}
</option>
</select>
<input class="search-query" type="text" ng-model="filter.values.value" placeholder="Value">
<button class="btn" ng-click="refresh()"
title="Filter">
<i class="icon-search">&nbsp;&nbsp;</i>
</button>
&nbsp;&nbsp;
<button class="btn pull-right" ng-click="reset()"
title="Reset">
<i class="icon-refresh">&nbsp;&nbsp;Reset</i>
</button>
</form>
</div>
<div class="pull-right">
<form class="form-inline">
<button class="btn-danger" ng-show="showClose"
ng-click="deleteDialog = true"
title="Close the selected Session">
<i class="icon-remove"></i> Close
</button>
&nbsp;&nbsp;&nbsp;
</form>
</div>
</div>
</div>
<div hawtio-confirm-dialog="deleteDialog"
ok-button-text="Close"
on-ok="closeSession()">
<div class="dialog-body">
<p>You are about to close the selected session: {{gridOptions.selectedItems[0].id}}
</p>
<p>Are you sure you want to continue.</p>
</div>
</div>
<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions" ui-grid-resize-columns ng-click="selectGridRow()"></div>
</div>
</div>

View File

@ -15,24 +15,6 @@
limitations under the License.
Architecture
-->
<style>
#scroll-box {
background:#e6e6e6;
width:100%;
height: 100%;
padding:0px;
overflow-y: scroll;
overflow-x: scroll
}
#help-content
{
position:absolute; left: 0; right: 0; bottom: 0; top: 106px;
}
</style>
<div ng-controller="Core.HelpController">
<div id="help-content">
<iframe id=scroll-box src="../user-manual/index.html" scrolling="yes" height="100%" width="100%" />
</div>
<div class="tree-nav-sidebar-content">
<div id="artemistree" class="treeview-pf-hover treeview-pf-select"></div>
</div>

View File

@ -0,0 +1,41 @@
<!--
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.
Architecture
-->
<div class="tree-nav-sidebar-header">
<form role="form" class="search-pf has-button">
<div class="form-group has-clear">
<div class="search-pf-input-group">
<label for="input-search" class="sr-only">Search Tree:</label>
<input id="input-search" type="search" class="form-control" placeholder="Search tree:"
ng-model="$ctrl.filter">
<button type="button" class="clear" aria-hidden="true"
ng-hide="$ctrl.filter.length === 0"
ng-click="$ctrl.filter = ''">
<span class="pficon pficon-close"></span>
</button>
</div>
</div>
<div class="form-group tree-nav-buttons">
<span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
ng-show="$ctrl.filter.length > 0">
{{$ctrl.result.length}}
</span>
<i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
<i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
</div>
</form>
</div>

View File

@ -1,120 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
/**
* @method AddressController
* @param $scope
* @param ARTEMISService
*
* Controller for the Create interface
*/
ARTEMIS.AddressController = function ($scope, workspace, ARTEMISService, jolokia, localStorage) {
Core.initPreferenceScope($scope, localStorage, {
'routingType': {
'value': 0,
'converter': parseInt,
'formatter': parseInt
}
});
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
$scope.workspace = workspace;
$scope.message = "";
$scope.deleteDialog = false;
$scope.$watch('workspace.selection', function () {
workspace.moveIfViewInvalid();
});
function operationSuccess() {
$scope.addressName = "";
$scope.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
$scope.workspace.loadTree();
}
function deleteSuccess() {
// lets set the selection to the parent
workspace.removeAndSelectParentNode();
$scope.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
$scope.workspace.loadTree();
}
$scope.createAddress = function (name, routingType) {
var mbean = getBrokerMBean(jolokia);
if (mbean) {
if (routingType == 0) {
$scope.message = "Created Multicast Address " + name;
ARTEMIS.log.info($scope.message);
ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "MULTICAST", onSuccess(operationSuccess));
}
else if (routingType == 1) {
$scope.message = "Created Anycast Address " + name;
ARTEMIS.log.info($scope.message);
ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST", onSuccess(operationSuccess));
}
else {
$scope.message = "Created Anycast/Multicast Address " + name;
ARTEMIS.log.info($scope.message);
ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST,MULTICAST", onSuccess(operationSuccess));
}
}
};
$scope.deleteAddress = function () {
var selection = workspace.selection;
var entries = selection.entries;
var mbean = getBrokerMBean(jolokia);
ARTEMIS.log.info(mbean);
if (mbean) {
if (selection && jolokia && entries) {
var domain = selection.domain;
var name = entries["address"];
name = name.unescapeHTML();
if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
{
name = name.substr(1,name.length -2);
}
name = ARTEMISService.artemisConsole.ownUnescape(name);
ARTEMIS.log.info(name);
var operation;
$scope.message = "Deleted address " + name;
ARTEMISService.artemisConsole.deleteAddress(mbean, jolokia, name, onSuccess(deleteSuccess));
}
}
};
$scope.name = function () {
var selection = workspace.selection;
if (selection) {
return ARTEMISService.artemisConsole.ownUnescape(selection.title);
}
return null;
};
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
}
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,234 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.AddressesController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisAddress) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "address";
var method = 'listAddresses(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'manage',
displayName: 'manage',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="navigateToAddressAtts(row)">attributes</a>&nbsp;<a ng-click="navigateToAddressOps(row)">operations</a></div>'
},
{
field: 'id',
displayName: 'ID',
width: '*'
},
{
field: 'name',
displayName: 'Name',
width: '*',
cellTemplate: '<div class="ngCellText" title="{{row.entity.name}}">{{row.entity.name}}</div>'
},
{
field: 'routingTypes',
displayName: 'Routing Types',
width: '*',
sortable: false
},
{
field: 'queueCount',
displayName: 'Queue Count',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectQueues(row)">{{row.entity.queueCount}}</a></div>',
sortable: false
}
];
ARTEMIS.log.debug('sessionStorage: addressesColumnDefs =', sessionStorage.getItem('addressesColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('addressesColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('addressesColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('addressesColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'NAME', name: 'Name'},
{id: 'ROUTING_TYPES', name: 'Routing Types'},
{id: 'QUEUE_COUNT', name: 'Queue Count'},
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "ID"
}
};
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
if (artemisAddress.address) {
$scope.filter.values.field = $scope.filter.fieldOptions[1].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisAddress.address.address;
artemisAddress.address = null;
}
$scope.navigateToAddressAtts = function (row) {
$location.path("jmx/attributes").search({"tab": "artemis", "nid": ARTEMIS.getAddressNid(row.entity, $location)});
};
$scope.navigateToAddressOps = function (row) {
$location.path("jmx/operations").search({"tab": "artemis", "nid": ARTEMIS.getAddressNid(row.entity, $location)});
};
$scope.selectQueues = function (row) {
artemisAddress.address = row.entity;
$location.path("artemis/queues");
};
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["id"],
columns: ["id"],
directions: ["asc"]
};
var refreshed = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -14,136 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var ARTEMIS;
(function (ARTEMIS) {
ARTEMIS.log = Logger.get("ARTEMIS");
ARTEMIS.jmxDomain = 'org.apache.ARTEMIS';
function getSelectionQueuesFolder(workspace) {
function findQueuesFolder(node) {
if (node) {
if (node.title === "Queues" || node.title === "Queue") {
return node;
}
var parent = node.parent;
if (parent) {
return findQueuesFolder(parent);
}
}
return null;
}
var Artemis;
(function (Artemis) {
function artemisJmxDomain() {
return localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
}
Artemis.artemisJmxDomain = artemisJmxDomain;;
function ownUnescape(name) {
//simple return unescape(name); does not work for this :(
return name.replace(/\\\\/g, "\\").replace(/\\\*/g, "*").replace(/\\\?/g, "?");
};
Artemis.ownUnescape = ownUnescape;
function getBrokerMBean(workspace, jolokia) {
var mbean = null;
var selection = workspace.selection;
if (selection) {
return findQueuesFolder(selection);
}
return null;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=\"" + folderNames[1] + "\"";
return mbean;
}
ARTEMIS.getSelectionQueuesFolder = getSelectionQueuesFolder;
function getSelectionTopicsFolder(workspace) {
function findTopicsFolder(node) {
var answer = null;
if (node) {
if (node.title === "Topics" || node.title === "Topic") {
answer = node;
}
if (answer === null) {
angular.forEach(node.children, function (child) {
if (child.title === "Topics" || child.title === "Topic") {
answer = child;
}
});
}
}
return answer;
}
var selection = workspace.selection;
if (selection) {
return findTopicsFolder(selection);
}
return null;
}
ARTEMIS.getSelectionTopicsFolder = getSelectionTopicsFolder;
/**
* Sets $scope.row to currently selected JMS message.
* Used in:
* - ARTEMIS/js/browse.ts
* - camel/js/browseEndpoint.ts
*
* TODO: remove $scope argument and operate directly on other variables. but it's too much side effects here...
*
* @param message
* @param key unique key inside message that distinguishes between values
* @param $scope
*/
function selectCurrentMessage(message, key, $scope) {
// clicking on message's link would interfere with messages selected with checkboxes
$scope.gridOptions.selectAll(false);
var idx = Core.pathGet(message, ["rowIndex"]);
var jmsMessageID = Core.pathGet(message, ["entity", key]);
$scope.rowIndex = idx;
var selected = $scope.gridOptions.selectedItems;
selected.splice(0, selected.length);
if (idx >= 0 && idx < $scope.messages.length) {
$scope.row = $scope.messages.find(function (msg) { return msg[key] === jmsMessageID; });
if ($scope.row) {
selected.push($scope.row);
}
}
else {
$scope.row = null;
}
}
ARTEMIS.selectCurrentMessage = selectCurrentMessage;
/**
* - Adds functions needed for message browsing with details
* - Adds a watch to deselect all rows after closing the slideout with message details
* TODO: export these functions too?
*
* @param $scope
*/
function decorate($scope) {
$scope.selectRowIndex = function (idx) {
$scope.rowIndex = idx;
var selected = $scope.gridOptions.selectedItems;
selected.splice(0, selected.length);
if (idx >= 0 && idx < $scope.messages.length) {
$scope.row = $scope.messages[idx];
if ($scope.row) {
selected.push($scope.row);
}
}
else {
$scope.row = null;
}
};
$scope.$watch("showMessageDetails", function () {
if (!$scope.showMessageDetails) {
$scope.row = null;
$scope.gridOptions.selectedItems.splice(0, $scope.gridOptions.selectedItems.length);
}
});
}
ARTEMIS.decorate = decorate;
Artemis.getBrokerMBean = getBrokerMBean;
function getAddressNid(address, $location) {
var rootNID = getRootNid($location);
var targetNID = rootNID + "-addresses-\"" + address.name + "\"";
ARTEMIS.log.info("targetNID=" + targetNID);
return targetNID;
}
ARTEMIS.getAddressNid = getAddressNid;
function getQueueNid(queue, $location) {
var rootNID = getRootNid($location);
var targetNID = rootNID + "-addresses-\"" + queue.address + "\"-queues-\"" + queue.routingType.toLowerCase() + "\"-\"" + queue.name + "\"";
return targetNID;
}
ARTEMIS.getQueueNid = getQueueNid;
function getRootNid($location) {
var currentNid = $location.search()['nid'];
var firstQoute = currentNid.indexOf('"');
var secondQuote = currentNid.indexOf('"', firstQoute + 1);
var rootNID = currentNid.substring(0, secondQuote + 1);
return rootNID;
}
})(ARTEMIS || (ARTEMIS = {}));
})(Artemis || (Artemis = {}));

View File

@ -15,355 +15,67 @@
* limitations under the License.
*/
/**
* @module ARTEMIS
* @main ARTEMIS
*
* The main entrypoint for the ARTEMIS module
*
* The main entry point for the Simple module
*/
var ARTEMIS = (function(ARTEMIS) {
var Artemis = (function (Artemis) {
/**
* @property pluginName
* @type {string}
*
/**
* The name of this plugin
*/
ARTEMIS.pluginName = "ARTEMIS";
Artemis.pluginName = 'artemis-plugin';
/**
* @property log
* @type {Logging.Logger}
*
/**
* This plugin's logger instance
*/
ARTEMIS.log = Logger.get(ARTEMIS.pluginName);
Artemis.log = Logger.get('artemis-plugin');
/**
* @property templatePath
* @type {string}
*
* The top level path to this plugin's partials
/**
* The top level path of this plugin on the server
*/
ARTEMIS.templatePath = "../artemis-plugin/plugin/html/";
Artemis.contextPath = "/artemis-plugin/";
/**
* @property jmxDomain
* @type {string}
*
* The JMX domain this plugin mostly works with
*/
ARTEMIS.jmxDomain = "hawtio"
Artemis.log.info("loading artemis plugin")
Artemis._module = angular.module(Artemis.pluginName, [
'angularResizable'
])
.component('artemis', {
template:
`<div class="tree-nav-layout">
<div class="sidebar-pf sidebar-pf-left" resizable r-directions="['right']">
<artemis-tree-header></artemis-tree-header>
<artemis-tree></artemis-tree>
</div>
<div class="tree-nav-main">
<artemis-navigation></artemis-navigation>
<div class="contents" ng-view></div>
</div>
</div>
`
})
.run(configurePlugin);
/**
* @property mbeanType
* @type {string}
*
* The mbean type this plugin will work with
*/
ARTEMIS.mbeanType = "ARTEMISHandler";
function configurePlugin(mainNavService, workspace, helpRegistry, preferencesRegistry, localStorage, preLogoutTasks, documentBase, $templateCache) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
mainNavService.addItem({
title: 'Artemis',
basePath: '/artemis',
template: '<artemis></artemis>',
isValid: function () { return workspace.treeContainsDomainAndProperties(artemisJmxDomain); }
});
/**
* @property mbean
* @type {string}
*
* The mbean's full object name
*/
ARTEMIS.mbean = ARTEMIS.jmxDomain + ":type=" + ARTEMIS.mbeanType;
// clean up local storage upon logout
preLogoutTasks.addTask('CleanupArtemisCredentials', function () {
Artemis.log.debug("Clean up Artemis credentials in local storage");
localStorage.removeItem('artemisUserName');
localStorage.removeItem('artemisPassword');
});
}
configurePlugin.$inject = ['mainNavService', 'workspace', 'helpRegistry', 'preferencesRegistry', 'localStorage', 'preLogoutTasks', 'documentBase', '$templateCache'];
/**
* @property SETTINGS_KEY
* @type {string}
*
* The key used to fetch our settings from local storage
*/
ARTEMIS.SETTINGS_KEY = 'ARTEMISSettings';
return Artemis;
/**
* @property module
* @type {object}
*
* This plugin's angularjs module instance
*/
ARTEMIS.module = angular.module(ARTEMIS.pluginName, ['bootstrap', 'ngResource', 'ui.bootstrap.dialog', 'hawtioCore', 'camel', 'hawtio-ui']);
})(Artemis || {});
// set up the routing for this plugin, these are referenced by the subleveltabs added below
ARTEMIS.module.config(function($routeProvider) {
$routeProvider
.when('/artemis/createAddress', {
templateUrl: ARTEMIS.templatePath + 'createAddress.html'
})
.when('/artemis/deleteAddress', {
templateUrl: ARTEMIS.templatePath + 'deleteAddress.html'
})
.when('/artemis/deleteQueue', {
templateUrl: ARTEMIS.templatePath + 'deleteQueue.html'
})
.when('/artemis/createQueue', {
templateUrl: ARTEMIS.templatePath + 'createQueue.html'
})
.when('/artemis/browseQueue', {
templateUrl: ARTEMIS.templatePath + 'browseQueue.html'
})
.when('/jmx/browseQueue', {
templateUrl: ARTEMIS.templatePath + 'browseQueue.html'
})
.when('/artemis/diagram', {
templateUrl: ARTEMIS.templatePath + 'brokerDiagram.html'
})
.when('/jmx/diagram', {
templateUrl: ARTEMIS.templatePath + 'brokerDiagram.html'
})
.when('/artemis/sendMessage', {
templateUrl: ARTEMIS.templatePath + 'sendMessage.html'
})
.when('/jmx/sendMessage', {
templateUrl: ARTEMIS.templatePath + 'sendMessage.html'
})
.when('/artemis/connections', {
templateUrl: ARTEMIS.templatePath + 'connections.html'
})
.when('/jmx/connections', {
templateUrl: ARTEMIS.templatePath + 'connections.html'
})
.when('/artemis/sessions', {
templateUrl: ARTEMIS.templatePath + 'sessions.html'
})
.when('/jmx/sessions', {
templateUrl: ARTEMIS.templatePath + 'sessions.html'
})
.when('/artemis/consumers', {
templateUrl: ARTEMIS.templatePath + 'consumers.html'
})
.when('/jmx/consumers', {
templateUrl: ARTEMIS.templatePath + 'consumers.html'
})
.when('/artemis/producers', {
templateUrl: ARTEMIS.templatePath + 'producers.html'
})
.when('/jmx/producers', {
templateUrl: ARTEMIS.templatePath + 'producers.html'
})
.when('/artemis/addresses', {
templateUrl: ARTEMIS.templatePath + 'addresses.html'
})
.when('/jmx/addresses', {
templateUrl: ARTEMIS.templatePath + 'addresses.html'
})
.when('/artemis/queues', {
templateUrl: ARTEMIS.templatePath + 'queues.html'
})
.when('/jmx/queues', {
templateUrl: ARTEMIS.templatePath + 'queues.html'
});
});
ARTEMIS.module.factory('artemisMessage', function () {
return { 'message': null };
});
ARTEMIS.module.factory('artemisConnection', function () {
return { 'connection': null };
});
ARTEMIS.module.factory('artemisSession', function () {
return { 'session': null };
});
ARTEMIS.module.factory('artemisConsumer', function () {
return { 'consumer': null };
});
ARTEMIS.module.factory('artemisProducer', function () {
return { 'producer': null };
});
ARTEMIS.module.factory('artemisQueue', function () {
return { 'queue': null };
});
ARTEMIS.module.factory('artemisAddress', function () {
return { 'address': null };
});
// one-time initialization happens in the run function
// of our module
ARTEMIS.module.run(function(workspace, viewRegistry, helpRegistry, preferencesRegistry, localStorage, jolokia, ARTEMISService, $rootScope, preLogoutTasks) {
// let folks know we're actually running
ARTEMIS.log.info("plugin running " + jolokia);
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
ARTEMISService.initArtemis();
// tell hawtio that we have our own custom layout for
// our view
viewRegistry["artemis"] = ARTEMIS.templatePath + "artemisLayout.html";
helpRegistry.addUserDoc("artemis", "../artemis-plugin/plugin/doc/help.md", function () {
return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
});
preferencesRegistry.addTab("Artemis", ARTEMIS.templatePath + "preferences.html", function () {
return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
});
// Add a top level tab to hawtio's navigation bar
workspace.topLevelTabs.push({
id: "artemis",
content: "Artemis",
title: "Artemis Broker",
isValid: function (workspace) {
return workspace.treeContainsDomainAndProperties(artemisJmxDomain);
},
href: function () {
return "#/jmx/attributes?tab=artemis";
},
isActive: function () {
return workspace.isLinkActive("artemis");
}
});
subLevelTabs = workspace.subLevelTabs;
subLevelTabs.push({
content: '<i class="icon-plus"></i> Create',
title: "Create a new address",
isValid: function (workspace) {
return isBroker(workspace, artemisJmxDomain) || isAddressFolder(workspace, artemisJmxDomain);
},
href: function () {
return "#/artemis/createAddress";
}
});
subLevelTabs.push({
content: '<i class="icon-remove"></i> Delete',
title: "Delete an address",
index: 4,
isValid: function (workspace) {
return isAddress(workspace, artemisJmxDomain);
},
href: function () {
return "#/artemis/deleteAddress";
}
});
subLevelTabs.push({
content: '<i class="icon-plus"></i> Create',
title: "Create a new queue",
isValid: function (workspace) {
return isAddress(workspace, artemisJmxDomain)
},
href: function () {
return "#/artemis/createQueue"
}
});
subLevelTabs.push({
content: '<i class="icon-remove"></i> Delete',
title: "Delete or purge this queue",
isValid: function (workspace) {
return isQueue(workspace, artemisJmxDomain);
},
href: function () {
return "#/artemis/deleteQueue"
}
});
subLevelTabs.push({
content: '<i class="icon-envelope"></i> Browse',
title: "Browse the messages on the queue",
isValid: function (workspace) {
return isQueue(workspace, artemisJmxDomain);
},
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/browseQueue"; else return "#/jmx/browseQueue";}
});
subLevelTabs.push({
content: '<i class="icon-pencil"></i> Send',
title: "Send a message to this address",
isValid: function (workspace) {
return isAddress(workspace, artemisJmxDomain) || isQueue(workspace, artemisJmxDomain);
},
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/sendMessage"; else return "#/jmx/sendMessage";}
});
subLevelTabs.unshift({
content: '<i class="icon-picture"></i> Diagram&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|',
title: "View a diagram of the producers, destinations and consumers",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis"))return "#/artemis/diagram"; else return "#/jmx/diagram";}
});
subLevelTabs.unshift({
content: '<i class="icon-th-list"></i> Queues',
title: "Manage Queues",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/queues"; else return "#/jmx/queues"; }
});
subLevelTabs.unshift({
content: '<i class="icon-book"></i> Addresses',
title: "Manage Addresses",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/addresses"; else return "#/jmx/addresses"; }
});
subLevelTabs.unshift({
content: '<i class="icon-upload-alt"></i> Producers',
title: "Manage Producers",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/producers"; else return "#/jmx/producers"; }
});
subLevelTabs.unshift({
content: '<i class="icon-download-alt"></i> Consumers',
title: "Manage Consumers",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/consumers"; else return "#/jmx/consumers"; }
});
subLevelTabs.unshift({
content: '<i class="icon-tasks"></i> Sessions',
title: "Manage Sessions",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/sessions"; else return "#/jmx/sessions"; }
});
subLevelTabs.unshift({
content: '<i class="icon-signal"></i> Connections',
title: "Manage Connections",
isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); },
href: function () { if (workspace.isTopTabActive("artemis")) return "#/artemis/connections"; else return "#/jmx/connections"; }
});
workspace.subLevelTabs = subLevelTabs;
preLogoutTasks.addTask("clearArtemisCredentials", function () {
localStorage.removeItem('artemisUserName');
localStorage.removeItem('artemisPassword');
});
});
function isBroker(workspace, domain) {
return workspace.hasDomainAndProperties(domain, {'broker': 'Broker'}, 3);
}
function isAddressFolder(workspace, domain) {
return workspace.selectionHasDomainAndLastFolderName(domain, 'addresses');
}
function isAddress(workspace, domain) {
return workspace.hasDomainAndProperties(domain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(domain, {'subcomponent': 'diverts'});
}
function isDivert(workspace, domain) {
return workspace.hasDomainAndProperties(domain, {'subcomponent': 'diverts'});
}
function isQueue(workspace, domain) {
return workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'});
}
return ARTEMIS;
}(ARTEMIS || {}));
// Very important! Add our module to hawtioPluginLoader so it
// bootstraps our module
hawtioPluginLoader.addModule(ARTEMIS.pluginName);
// tell the Hawtio plugin loader about our plugin so it can be
// bootstrapped with the rest of AngularJS
hawtioPluginLoader.addModule(Artemis.pluginName);

View File

@ -1,44 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.SERVER = 'Server Messages';
// The ARTEMIS service handles the connection to
// the Artemis Jolokia server in the background
ARTEMIS.module.factory("ARTEMISService", function(jolokia, $rootScope) {
var self = {
artemisConsole: undefined,
getVersion: function(jolokia) {
ARTEMIS.log.info("Connecting to ARTEMIS service: " + self.artemisConsole.getServerAttributes(jolokia));
} ,
initArtemis: function(broker) {
ARTEMIS.log.info("*************creating Artemis Console************");
self.artemisConsole = new ArtemisConsole();
}
};
return self;
});
return ARTEMIS;
}(ARTEMIS || {}));

View File

@ -1,687 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.BrokerDiagramController = function ($scope, $compile, $location, localStorage, ARTEMISService, jolokia, workspace, $routeParams) {
Fabric.initScope($scope, $location, jolokia, workspace);
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
$scope.selectedNode = null;
var defaultFlags = {
panel: true,
popup: false,
label: true,
group: false,
profile: false,
slave: false,
broker: true,
network: true,
container: false,
address: true,
queue: true,
consumer: true,
producer: true
};
$scope.viewSettings = {};
$scope.shapeSize = {
broker: 20,
queue: 14,
address: 14
};
var redrawGraph = Core.throttled(doRedrawGraph, 1000);
var graphBuilder = new ForceGraph.GraphBuilder();
Core.bindModelToSearchParam($scope, $location, "searchFilter", "q", "");
angular.forEach(defaultFlags, function (defaultValue, key) {
var modelName = "viewSettings." + key;
// bind model values to search params...
function currentValue() {
var answer = $location.search()[paramName] || defaultValue;
return answer === "false" ? false : answer;
}
var paramName = key;
var value = currentValue();
Core.pathSet($scope, modelName, value);
$scope.$watch(modelName, function () {
var current = Core.pathGet($scope, modelName);
var old = currentValue();
if (current !== old) {
var defaultValue = defaultFlags[key];
if (current !== defaultValue) {
if (!current) {
current = "false";
}
$location.search(paramName, current);
}
else {
$location.search(paramName, null);
}
}
redrawGraph();
});
});
$scope.connectToBroker = function () {
var selectedNode = $scope.selectedNode;
if (selectedNode) {
var container = selectedNode["brokerContainer"] || selectedNode;
connectToBroker(container, selectedNode["brokerName"]);
}
};
function connectToBroker(container, brokerName, postfix) {
if (postfix === void 0) {
postfix = null;
}
var view = "/jmx/attributes?tab=artemis";
if (!postfix) {
if (brokerName) {
// lets default to the broker view
postfix = "nid=root-" + artemisJmxDomain + "-Broker-" + brokerName;
}
}
if (postfix) {
view += "&" + postfix;
}
var path = Core.url("/#" + view);
window.open(path, '_destination');
window.focus();
}
$scope.$on('$destroy', function (event) {
stopOldJolokia();
});
function stopOldJolokia() {
var oldJolokia = $scope.selectedNodeJolokia;
if (oldJolokia && oldJolokia !== jolokia) {
oldJolokia.stop();
}
}
$scope.$watch("selectedNode", function (newValue, oldValue) {
// lets cancel any previously registered thingy
if ($scope.unregisterFn) {
$scope.unregisterFn();
$scope.unregisterFn = null;
}
var node = $scope.selectedNode;
if (node) {
var mbean = node.objectName;
var brokerContainer = node.brokerContainer || {};
var nodeJolokia = node.jolokia || brokerContainer.jolokia || jolokia;
if (nodeJolokia !== $scope.selectedNodeJolokia) {
stopOldJolokia();
$scope.selectedNodeJolokia = nodeJolokia;
if (nodeJolokia !== jolokia) {
var rate = Core.parseIntValue(localStorage['updateRate'] || "2000", "update rate");
if (rate) {
nodeJolokia.start(rate);
}
}
}
var dummyResponse = {value: node.panelProperties || {}};
if (mbean && nodeJolokia) {
ARTEMIS.log.debug("reading ", mbean, " on remote container");
$scope.unregisterFn = Core.register(nodeJolokia, $scope, {
type: 'read',
mbean: mbean
}, onSuccess(renderNodeAttributes, {
error: function (response) {
// probably we've got a wrong mbean name?
// so lets render at least
renderNodeAttributes(dummyResponse);
Core.defaultJolokiaErrorHandler(response);
}
}));
}
else {
ARTEMIS.log.debug("no mbean or jolokia available, using dummy response");
renderNodeAttributes(dummyResponse);
}
}
});
function getDestinationTypeName(attributes) {
var prefix = attributes["DestinationTemporary"] ? "Temporary " : "";
return prefix + (attributes["DestinationTopic"] ? "Topic" : "Queue");
}
var ignoreNodeAttributes = ["Broker", "BrokerId", "BrokerName", "Connection", "DestinationName", "DestinationQueue", "DestinationTemporary", "DestinationTopic",];
var ignoreNodeAttributesByType = {
producer: ["Producer", "ProducerId"],
queue: ["Name", "MessageGroups", "MessageGroupType", "Subscriptions"],
topic: ["Name", "Subscriptions"],
broker: ["DataDirectory", "DurableTopicSubscriptions", "DynamicDestinationProducers", "InactiveDurableToppicSubscribers"]
};
var brokerShowProperties = ["Version", "Started"];
var onlyShowAttributesByType = {
broker: brokerShowProperties,
brokerSlave: brokerShowProperties
};
function renderNodeAttributes(response) {
var properties = [];
if (response) {
var value = response.value || {};
$scope.selectedNodeAttributes = value;
var selectedNode = $scope.selectedNode || {};
var brokerContainer = selectedNode['brokerContainer'] || {};
var nodeType = selectedNode["type"];
var brokerName = selectedNode["brokerName"];
var containerId = selectedNode["container"] || brokerContainer["container"];
var group = selectedNode["group"] || brokerContainer["group"];
var jolokiaUrl = selectedNode["jolokiaUrl"] || brokerContainer["jolokiaUrl"];
var profile = selectedNode["profile"] || brokerContainer["profile"];
var version = selectedNode["version"] || brokerContainer["version"];
var isBroker = nodeType && nodeType.startsWith("broker");
var ignoreKeys = ignoreNodeAttributes.concat(ignoreNodeAttributesByType[nodeType] || []);
var onlyShowKeys = onlyShowAttributesByType[nodeType];
angular.forEach(value, function (v, k) {
if (onlyShowKeys ? onlyShowKeys.indexOf(k) >= 0 : ignoreKeys.indexOf(k) < 0) {
var formattedValue = Core.humanizeValueHtml(v);
properties.push({key: Core.humanizeValue(k), value: formattedValue});
}
});
properties = properties.sortBy("key");
var brokerProperty = null;
if (brokerName) {
var brokerHtml = '<a target="broker" ng-click="connectToBroker()">' + '<img title="Apache Artemis" src="img/icons/messagebroker.svg"> ' + brokerName + '</a>';
if (version && profile) {
var brokerLink = Fabric.brokerConfigLink(workspace, jolokia, localStorage, version, profile, brokerName);
if (brokerLink) {
brokerHtml += ' <a title="configuration settings" target="brokerConfig" href="' + brokerLink + '"><i class="icon-tasks"></i></a>';
}
}
var html = $compile(brokerHtml)($scope);
brokerProperty = {key: "Broker", value: html};
if (!isBroker) {
properties.splice(0, 0, brokerProperty);
}
}
if (containerId) {
properties.splice(0, 0, {
key: "Container",
value: $compile('<div fabric-container-link="' + selectedNode['container'] + '"></div>')($scope)
});
}
var destinationName = value["DestinationName"] || selectedNode["destinationName"];
if (destinationName && (nodeType !== "queue" && nodeType !== "topic")) {
var destinationTypeName = getDestinationTypeName(value);
var html = createDestinationLink(destinationName, destinationTypeName);
properties.splice(0, 0, {key: destinationTypeName, value: html});
}
var typeLabel = selectedNode["typeLabel"];
var name = selectedNode["name"] || selectedNode["id"] || selectedNode['objectName'];
if (typeLabel) {
var html = name;
if (nodeType === "queue" || nodeType === "topic") {
html = createDestinationLink(name, nodeType);
}
var typeProperty = {key: typeLabel, value: html};
if (isBroker && brokerProperty) {
typeProperty = brokerProperty;
}
properties.splice(0, 0, typeProperty);
}
}
$scope.selectedNodeProperties = properties;
Core.$apply($scope);
}
function createDestinationLink(destinationName, destinationType) {
return Core.escapeHtml(destinationName);
}
$scope.$watch("searchFilter", function (newValue, oldValue) {
redrawGraph();
});
// lets just use the current stuff from the workspace
$scope.$watch('workspace.tree', function () {
redrawGraph();
});
$scope.$on('jmxTreeUpdated', function () {
redrawGraph();
});
function onBrokerData(response) {
if (response) {
var responseJson = angular.toJson(response.value);
if ($scope.responseJson === responseJson) {
return;
}
$scope.responseJson = responseJson;
$scope.brokers = response.value;
doRedrawGraph();
}
}
function redrawLocalBroker() {
var container = {
jolokia: jolokia
};
var containerId = "local";
$scope.activeContainers = {
containerId: container
};
var brokers = [];
jolokia.search(artemisJmxDomain + ":broker=*", onSuccess(function (response) {
angular.forEach(response, function (objectName) {
var atts = ARTEMISService.artemisConsole.getServerAttributes(jolokia, objectName);
var val = atts.value;
var details = Core.parseMBean(objectName);
if (details) {
var properties = details['attributes'];
ARTEMIS.log.info("Got broker: " + objectName + " on container: " + containerId + " properties: " + angular.toJson(properties, true));
if (properties) {
var brokerId = properties["broker"] || "unknown";
var brokerName = artemisJmxDomain + ":broker=" + brokerId;
var backupRes = ARTEMISService.artemisConsole.isBackup(jolokia, brokerName);
var isBackup = backupRes.value;
var nodeId = val["NodeID"];
var theBroker = {
brokerId: brokerId,
nodeId: nodeId
};
brokers.push(theBroker);
if ($scope.viewSettings.broker) {
var broker = getOrAddBroker(!isBackup, brokerId, nodeId, containerId, container, properties);
}
}
}
});
redrawActiveContainers(brokers);
}));
}
function redrawActiveContainers(brokers) {
// TODO delete any nodes from dead containers in containersToDelete
angular.forEach($scope.activeContainers, function (container, id) {
var containerJolokia = container.jolokia;
if (containerJolokia) {
onContainerJolokia(containerJolokia, container, id, brokers);
}
else {
Fabric.containerJolokia(jolokia, id, function (containerJolokia) {
return onContainerJolokia(containerJolokia, container, id, brokers);
});
}
});
$scope.graph = graphBuilder.buildGraph();
Core.$apply($scope);
}
function doRedrawGraph() {
graphBuilder = new ForceGraph.GraphBuilder();
redrawLocalBroker();
}
function brokerNameMarkup(brokerName) {
return brokerName ? "<p></p>broker: " + brokerName + "</p>" : "";
}
function onContainerJolokia(containerJolokia, container, id, brokers) {
function createQueues(brokers) {
if ($scope.viewSettings.queue) {
containerJolokia.search(artemisJmxDomain + ":*,subcomponent=queues", onSuccess(function (response) {
angular.forEach(response, function (objectName) {
var details = Core.parseMBean(objectName);
if (details) {
var properties = details['attributes'];
if (properties) {
configureDestinationProperties(properties);
var brokerName = properties.broker;
var addressName = properties.address;
var typeName = "queue";
var queueName = properties.queue;
var routingType = properties["routing-type"];
var destination = getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName);
}
}
});
graphModelUpdated();
createConsumersAndNetwork(brokers);
}));
} else {
createConsumersAndNetwork(brokers);
}
}
function createAddresses(brokers) {
if ($scope.viewSettings.address) {
containerJolokia.search(artemisJmxDomain + ":*,component=addresses", onSuccess(function (response) {
angular.forEach(response, function (objectName) {
var details = Core.parseMBean(objectName);
if (details) {
var properties = details['attributes'];
if (properties) {
var brokerName = properties.broker;
var typeName = "address";
var addressName = properties.address;
var destination = getOrAddAddress(properties, typeName, addressName, brokerName);
}
}
});
createQueues(brokers);
graphModelUpdated();
}));
} else {
createQueues(brokers);
}
}
function createConsumersAndNetwork(brokers) {
angular.forEach(brokers, function (broker) {
mBean = artemisJmxDomain + ":broker=" + broker.brokerId;
// find consumers
if ($scope.viewSettings.consumer) {
ARTEMISService.artemisConsole.getConsumers(mBean, containerJolokia, onSuccess(function (properties) {
consumers = properties.value;
angular.forEach(angular.fromJson(consumers), function (consumer) {
if (consumer) {
configureDestinationProperties(consumer);
var consumerId = consumer.sessionID + "-" + consumer.consumerID;
if (consumerId) {
var queueName = consumer.queueName;
var consumerNode = getOrAddNode("consumer", consumerId, consumer, function () {
return {
typeLabel: "Consumer",
brokerContainer: container,
jolokia: containerJolokia,
popup: {
title: "Consumer: " + Core.escapeHtml(consumerId),
content: "<p>client: " + Core.escapeHtml(consumer.connectionID || "") + "</p> " + brokerNameMarkup(broker.brokerId)
}
};
});
addLinkIds("queue:\"" + queueName + "\"", consumerNode["id"], "consumer");
}
}
});
graphModelUpdated();
}));
}
// find networks of brokers
if ($scope.viewSettings.network && $scope.viewSettings.broker) {
ARTEMISService.artemisConsole.getRemoteBrokers(mBean, containerJolokia, onSuccess(function (properties) {
remoteBrokers = properties.value;
var remoteBrokersObj = angular.fromJson(remoteBrokers);
var newBackReq = ARTEMISService.artemisConsole.isBackup(jolokia, mBean);
var newBackup = newBackReq.value;
angular.forEach(remoteBrokersObj, function (remoteBroker) {
if (broker.nodeId != remoteBroker.nodeID) {
if (remoteBroker.live) {
getOrAddBroker(true, "\"" + remoteBroker.live + "\"", remoteBroker.nodeID, "remote", null, properties);
}
if (remoteBroker.backup) {
getOrAddBroker(false, "\"" + remoteBroker.backup + "\"", remoteBroker.nodeID, "remote", null, properties);
}
} else {
if (!newBackup) {
getOrAddBroker(false, "\"" + remoteBroker.backup + "\"", remoteBroker.nodeID, "remote", null, properties);
} else {
getOrAddBroker(true, "\"" + remoteBroker.live + "\"", remoteBroker.nodeID, "remote", null, properties);
}
}
});
var processedLiveBrokers = [];
angular.forEach(remoteBrokersObj, function (remoteBroker) {
if (remoteBroker) {
if (remoteBroker.live) {
angular.forEach(processedLiveBrokers, function(livebroker) {
//because the local broker has a different id format we need to identify it
if (broker.nodeId == livebroker.nodeID) {
if (!newBackup) {
addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.live + "\"", "network");
} else {
//I am backup
addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
}
} else if (broker.nodeId == remoteBroker.nodeID) {
if (!newBackup) {
addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + livebroker.live + "\"", "network");
} else {
//I am backup
addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
}
} else {
addLinkIds("broker:" + "\"" + livebroker.live + "\"", "broker:" + "\"" + remoteBroker.live + "\"", "network");
}
});
processedLiveBrokers.push(remoteBroker);
}
//now backups
if (broker.nodeId != remoteBroker.nodeID) {
if (remoteBroker.backup) {
addLinkIds("broker:" + "\"" + remoteBroker.live + "\"", "broker:" + "\"" + remoteBroker.backup + "\"", "network");
}
}
else {
if (!newBackup) {
if (remoteBroker.backup) {
addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.backup + "\"", "network");
}
}
else {
//I am backup
addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.live + "\"", "network");
}
}
}
});
graphModelUpdated();
}));
}
});
}
if (containerJolokia) {
container.jolokia = containerJolokia;
function getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName) {
var queue = getOrAddNode(typeName.toLowerCase(), queueName, properties, function () {
var objectName = "";
if (addressName) {
objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName;
}
var answer = {
typeLabel: typeName,
brokerContainer: container,
objectName: objectName,
jolokia: containerJolokia,
popup: {
title: "queue: " + Core.escapeHtml(queueName),
content: "address:" + Core.escapeHtml(addressName)
}
};
if (!addressName) {
containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName + ",*", onSuccess(function (response) {
if (response && response.length) {
answer.objectName = response[0];
}
}));
}
return answer;
});
if (queue && $scope.viewSettings.broker && addressName) {
addLinkIds("address:" + addressName, queue["id"], "queue");
}
return queue;
}
function getOrAddAddress(properties, typeName, destinationName, brokerName) {
var destination = getOrAddNode(typeName.toLowerCase(), destinationName, properties, function () {
var objectName = "";
if (brokerName) {
objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName;
}
var answer = {
typeLabel: typeName,
brokerContainer: container,
objectName: objectName,
jolokia: containerJolokia,
popup: {
title: typeName + ": " + destinationName,
content: brokerNameMarkup(brokerName)
}
};
if (!brokerName) {
containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName + ",*", onSuccess(function (response) {
if (response && response.length) {
answer.objectName = response[0];
}
}));
}
return answer;
});
if (destination && $scope.viewSettings.broker && brokerName) {
addLinkIds(brokerNodeId(brokerName), destination["id"], "address");
}
return destination;
}
createAddresses(brokers);
}
}
function graphModelUpdated() {
$scope.graph = graphBuilder.buildGraph();
Core.$apply($scope);
}
function getOrAddBroker(master, brokerId, nodeId, containerId, container, brokerStatus) {
var broker = null;
var brokerFlag = master ? $scope.viewSettings.broker : $scope.viewSettings.slave;
if (brokerFlag) {
broker = getOrAddNode("broker", brokerId, brokerStatus, function () {
return {
type: master ? "broker" : "brokerSlave",
typeLabel: master ? "Broker" : "Slave Broker",
popup: {
title: (master ? "Master" : "Slave") + " Broker: " + brokerId,
content: "<p>Container: " + containerId + "</p> Node ID: " + nodeId
}
};
});
if (!broker['objectName']) {
// lets try guess the mbean name
broker['objectName'] = artemisJmxDomain + ":broker=" + brokerId;
ARTEMIS.log.debug("Guessed broker mbean: " + broker['objectName']);
}
if (!broker['brokerContainer'] && container) {
broker['brokerContainer'] = container;
}
if (!broker['nodeID']) {
broker['nodeID'] = nodeId;
}
}
return broker;
}
function getOrAddNode(typeName, id, properties, createFn) {
var node = null;
if (id) {
var nodeId = typeName + ":" + id;
node = graphBuilder.getNode(nodeId);
if (!node) {
var nodeValues = createFn();
node = angular.copy(properties);
angular.forEach(nodeValues, function (value, key) {
return node[key] = value;
});
node['id'] = nodeId;
if (!node['type']) {
node['type'] = typeName;
}
if (!node['name']) {
node['name'] = id;
}
if (node) {
var size = $scope.shapeSize[typeName];
if (size && !node['size']) {
node['size'] = size;
}
if (!node['summary']) {
node['summary'] = node['popup'] || "";
}
if (!$scope.viewSettings.popup) {
delete node['popup'];
}
if (!$scope.viewSettings.label) {
delete node['name'];
}
// lets not add nodes which are defined as being disabled
var enabled = $scope.viewSettings[typeName];
if (enabled || !angular.isDefined(enabled)) {
graphBuilder.addNode(node);
}
else {
}
}
}
}
return node;
}
function addLink(object1, object2, linkType) {
if (object1 && object2) {
addLinkIds(object1.id, object2.id, linkType);
}
}
function addLinkIds(id1, id2, linkType) {
if (id1 && id2) {
graphBuilder.addLink(id1, id2, linkType);
}
}
function brokerNodeId(brokerId) {
return brokerId ? "broker:" + brokerId : null;
}
/**
* Avoid the JMX type property clashing with the ForceGraph type property; used for associating css classes with nodes on the graph
*
* @param properties
*/
function renameTypeProperty(properties) {
properties.mbeanType = properties['type'];
delete properties['type'];
}
function configureDestinationProperties(properties) {
renameTypeProperty(properties);
var destinationType = properties.destinationType || "Queue";
var typeName = destinationType.toLowerCase();
properties.isQueue = !typeName.startsWith("t");
properties['destType'] = typeName;
}
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,593 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.BrowseQueueController = function($scope, workspace, ARTEMISService, jolokia, localStorage, artemisMessage, $location, $timeout) {
var defaultAttributes = [{
field: 'messageID',
displayName: 'Message ID',
cellTemplate: '<div class="ngCellText"><a ng-click="openMessageDialog(row)">{{row.entity.messageID}}</a></div>',
// for ng-grid
width: '100px'
}, {
field: 'type',
displayName: 'Type',
cellTemplate: '<div class="ngCellText" title="{{row.entity.type}}">{{formatType(row.entity.type)}}</div>',
width: '90px'
}, {
field: 'durable',
displayName: 'Durable',
width: '70px'
}, {
field: 'priority',
displayName: 'Priority',
width: '70px'
}, {
field: 'timestamp',
displayName: 'Timestamp',
cellTemplate: '<div class="ngCellText" title="{{row.entity.timestamp}}">{{formatTimestamp(row.entity.timestamp)}}</div>',
width: '160px'
}, {
field: 'expiration',
displayName: 'Expires',
cellTemplate: '<div class="ngCellText" title="{{row.entity.expiration}}">{{formatExpires(row.entity.expiration)}}</div>',
width: '160px'
}, {
field: 'redelivered',
displayName: 'Redelivered',
width: '100px'
}, {
field: 'largeMessage',
displayName: 'Large',
width: '50px'
}, {
field: 'persistentSize',
displayName: 'Persistent Size',
cellTemplate: '<div class="ngCellText" title="{{row.entity.persistentSize.toLocaleString()}} bytes">{{formatPersistentSize(row.entity.persistentSize)}}</div>',
width: '120px'
}, {
field: 'userID',
displayName: 'User ID',
width: '15%'
}, {
displayName: 'Validated User',
cellTemplate: '<div class="ngCellText">{{row.entity.StringProperties._AMQ_VALIDATED_USER}}</div>',
width: '*'
}];
var attributes = defaultAttributes;
if (sessionStorage.getItem('browseColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('browseColumnDefs'));
}
$scope.$on('ngGridEventColumns', function(newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function(visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function(attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('browseColumnDefs', JSON.stringify(attributes));
});
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.totalServerItems = 0;
$scope.searchText = '';
$scope.allMessages = [];
$scope.messages = [];
$scope.headers = {};
$scope.mode = 'text';
$scope.deleteDialog = false;
$scope.moveDialog = false;
$scope.gridOptions = {
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
showFooter: true,
selectedItems: [],
data: 'messages',
displayFooter: false,
showFilter: false,
showColumnMenu: true,
enableColumnResize: true,
enableColumnReordering: true,
enableHighlighting: true,
filterOptions: {
filterText: '',
useExternalFilter: true
},
selectWithCheckboxOnly: true,
showSelectionCheckbox: true,
maintainColumnRatios: false,
columnDefs: attributes,
afterSelectionChange: afterSelectionChange
};
$scope.showMessageDetails = false;
var ignoreColumns = ["PropertiesText", "BodyPreview", "text"];
var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"];
$scope.$watch('workspace.selection', function() {
if (workspace.moveIfViewInvalid()) {
return;
}
// lets defer execution as we may not have the selection just yet
setTimeout(loadTable, 50);
});
$scope.$watch('gridOptions.filterOptions.filterText', function(filterText) {
filterMessages(filterText);
});
$scope.$watch('pagingOptions', function(newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
loadTable();
}
}, true);
$scope.openMessageDialog = function(message) {
ARTEMIS.selectCurrentMessage(message, "messageID", $scope);
if ($scope.row) {
$scope.mode = CodeEditor.detectTextFormat($scope.row.Text);
$scope.showMessageDetails = true;
}
};
$scope.refresh = loadTable;
ARTEMIS.decorate($scope);
var MS_PER_SEC = 1000;
var MS_PER_MIN = 60 * MS_PER_SEC;
var MS_PER_HOUR = 60 * MS_PER_MIN;
var MS_PER_DAY = 24 * MS_PER_HOUR;
function pad2(value) {
return (value < 10 ? '0' : '') + value;
}
$scope.formatExpires = function(timestamp) {
if (isNaN(timestamp)) {
return timestamp;
}
var expiresIn = timestamp - Date.now();
if (Math.abs(expiresIn) < MS_PER_DAY) {
var duration = expiresIn < 0 ? -expiresIn : expiresIn;
var hours = pad2(Math.floor((duration / MS_PER_HOUR) % 24));
var mins = pad2(Math.floor((duration / MS_PER_MIN) % 60));
var secs = pad2(Math.floor((duration / MS_PER_SEC) % 60));
if (expiresIn < 0) {
// "HH:mm:ss ago"
return hours + ":" + mins + ":" + secs + " ago";
}
// "in HH:mm:ss ago"
return "in " + hours + ":" + mins + ":" + secs;
}
return $scope.formatTimestamp(timestamp);
}
$scope.formatTimestamp = function(timestamp) {
if (isNaN(timestamp)) {
return timestamp;
}
var d = new Date(timestamp);
// "yyyy-MM-dd HH:mm:ss"
//add 1 to month as getmonth returns the position not the actual month
return d.getFullYear() + "-" + pad2(d.getMonth() + 1) + "-" + pad2(d.getDate()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
}
var typeLabels = ["default", "1", "object", "text", "bytes", "map", "stream", "embedded"];
$scope.formatType = function(type) {
if (isNaN(type)) {
return type;
}
return type > -1 && type < 8 ? typeLabels[type] : type
}
$scope.formatPersistentSize = function(bytes) {
if(isNaN(bytes) || bytes < 0) return "n/a";
if(bytes < 10240) return bytes.toLocaleString() + " Bytes";
if(bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
if(bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
return (bytes / 1073741824).toFixed(2) + " GB";
}
$scope.moveMessages = function() {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $scope.gridOptions.selectedItems;
$scope.message = "Moved " + Core.maybePlural(selectedItems.length, "message" + " to " + $scope.queueName);
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : moveSuccess;
ARTEMISService.artemisConsole.moveMessage(mbean, jolokia, id, $scope.queueName, onSuccess(callback));
}
});
}
};
$scope.resendMessage = function() {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $scope.gridOptions.selectedItems;
// always assume a single message
artemisMessage.message = selectedItems[0];
$location.path('artemis/sendMessage');
}
};
$scope.deleteMessages = function() {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $scope.gridOptions.selectedItems;
$scope.message = "Deleted " + Core.maybePlural(selectedItems.length, "message");
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
ARTEMISService.artemisConsole.deleteMessage(mbean, jolokia, id, onSuccess(callback));
}
});
}
};
$scope.retryMessages = function() {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $scope.gridOptions.selectedItems;
$scope.message = "Retry " + Core.maybePlural(selectedItems.length, "message");
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
ARTEMISService.artemisConsole.retryMessage(mbean, jolokia, id, onSuccess(callback));
}
});
}
};
$scope.queueNames = function(completionText) {
var queuesFolder = ARTEMIS.getSelectionQueuesFolder(workspace);
if (queuesFolder) {
var selectedQueue = workspace.selection.key;
var otherQueues = queuesFolder.children.exclude(function(child) {
return child.key == selectedQueue;
});
return (otherQueues) ? otherQueues.map(function(n) {
return n.title;
}) : [];
} else {
return [];
}
};
function populateTable(response) {
var data = response.value;
ARTEMIS.log.info("loading data:" + data);
if (!angular.isArray(data)) {
$scope.allMessages = [];
angular.forEach(data, function(value, idx) {
$scope.allMessages.push(value);
});
} else {
$scope.allMessages = data;
}
angular.forEach($scope.allMessages, function(message) {
message.headerHtml = createHeaderHtml(message);
message.bodyText = createBodyText(message);
});
filterMessages($scope.gridOptions.filterOptions.filterText);
Core.$apply($scope);
}
/*
* For some reason using ng-repeat in the modal dialog doesn't work so lets
* just create the HTML in code :)
*/
function createBodyText(message) {
ARTEMIS.log.info("loading message:" + message);
if (message.text) {
var body = message.text;
var lenTxt = "" + body.length;
message.textMode = "text (" + lenTxt + " chars)";
return body;
} else if (message.BodyPreview) {
var code = Core.parseIntValue(localStorage["ARTEMISBrowseBytesMessages"] || "1", "browse bytes messages");
var body;
message.textMode = "bytes (turned off)";
if (code != 99) {
var bytesArr = [];
var textArr = [];
message.BodyPreview.forEach(function(b) {
if (code === 1 || code === 2) {
// text
textArr.push(String.fromCharCode(b));
}
if (code === 1 || code === 4) {
// hex and must be 2 digit so they space out evenly
var s = b.toString(16);
if (s.length === 1) {
s = "0" + s;
}
bytesArr.push(s);
} else {
// just show as is without spacing out, as that is usually more used for hex than decimal
var s = b.toString(10);
bytesArr.push(s);
}
});
var bytesData = bytesArr.join(" ");
var textData = textArr.join("");
if (code === 1 || code === 2) {
// bytes and text
var len = message.BodyPreview.length;
var lenTxt = "" + textArr.length;
body = "bytes:\n" + bytesData + "\n\ntext:\n" + textData;
message.textMode = "bytes (" + len + " bytes) and text (" + lenTxt + " chars)";
} else {
// bytes only
var len = message.BodyPreview.length;
body = bytesData;
message.textMode = "bytes (" + len + " bytes)";
}
}
return body;
} else {
message.textMode = "unsupported";
return "Unsupported message body type which cannot be displayed by hawtio";
}
}
/*
* For some reason using ng-repeat in the modal dialog doesn't work so lets
* just create the HTML in code :)
*/
function createHeaderHtml(message) {
var headers = createHeaders(message);
var properties = createProperties(message);
var headerKeys = Object.extended(headers).keys();
function sort(a, b) {
if (a > b)
return 1;
if (a < b)
return -1;
return 0;
}
var propertiesKeys = Object.extended(properties).keys().sort(sort);
var jmsHeaders = headerKeys.filter(function(key) {
return key.startsWith("JMS");
}).sort(sort);
var remaining = headerKeys.subtract(jmsHeaders, propertiesKeys).sort(sort);
var buffer = [];
function appendHeader(key) {
var value = headers[key];
if (value === null) {
value = '';
}
if (key == "expiration" || key == "timestamp") {
value = $scope.formatTimestamp(value) + " (" + value + ")";
} else if (key == "type") {
value = $scope.formatType(value) + " (" + value + ")";
}
buffer.push('<tr><td class="propertyName"><span class="green">Header</span> - ' + key + '</td><td class="property-value">' + value + '</td></tr>');
}
function appendProperty(key) {
var value = properties[key];
if (value === null) {
value = '';
}
buffer.push('<tr><td class="propertyName">' + key + '</td><td class="property-value">' + value + '</td></tr>');
}
jmsHeaders.forEach(appendHeader);
remaining.forEach(appendHeader);
propertiesKeys.forEach(appendProperty);
return buffer.join("\n");
}
function createHeaders(row) {
var answer = {};
angular.forEach(row, function(value, key) {
if (!ignoreColumns.any(key) && !flattenColumns.any(key)) {
answer[Core.escapeHtml(key)] = Core.escapeHtml(value);
}
});
return answer;
}
function createProperties(row) {
ARTEMIS.log.debug("properties: ", row);
var answer = {};
angular.forEach(row, function(value, key) {
if (!ignoreColumns.any(key) && flattenColumns.any(key)) {
angular.forEach(value, function(v2, k2) {
answer['<span class="green">' + key.replace('Properties', ' Property') + '</span> - ' + Core.escapeHtml(k2)] = Core.escapeHtml(v2);
});
}
});
return answer;
}
function loadTable() {
ARTEMIS.log.info("loading table")
var objName;
$scope.gridOptions.selectedItems.length = 0;
if (workspace.selection) {
objName = workspace.selection.objectName;
} else {
// in case of refresh
var key = location.search()['nid'];
var node = workspace.keyToNodeMap[key];
objName = node.objectName;
}
if (objName) {
$scope.dlq = false;
var queueName = jolokia.getAttribute(objName, "Name");
var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
ARTEMIS.log.info("loading table" + artemisExpiryQueue);
if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
onDlq(true);
} else {
onDlq(false);
}
jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, onSuccess(function(response) { $scope.totalServerItems = response.value; }));
jolokia.request({ type: 'exec', mbean: objName, operation: 'browse(int, int)', arguments: [$scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable));
}
}
function onDlq(response) {
ARTEMIS.log.info("onDLQ=" + response);
$scope.dlq = response;
Core.$apply($scope);
}
function intermediateResult() {
}
function operationSuccess() {
$scope.messageDialog = false;
deselectAll();
Core.notification("success", $scope.message);
loadTable();
setTimeout(loadTable, 50);
}
function moveSuccess() {
operationSuccess();
workspace.loadTree();
}
function filterMessages(filter) {
var searchConditions = buildSearchConditions(filter);
evalFilter(searchConditions);
}
function evalFilter(searchConditions) {
if (!searchConditions || searchConditions.length === 0) {
$scope.messages = $scope.allMessages;
} else {
ARTEMIS.log.debug("Filtering conditions:", searchConditions);
$scope.messages = $scope.allMessages.filter(function(message) {
ARTEMIS.log.debug("Message:", message);
var matched = true;
$.each(searchConditions, function(index, condition) {
if (!condition.column) {
matched = matched && evalMessage(message, condition.regex);
} else {
matched = matched && (message[condition.column] && condition.regex.test(message[condition.column])) || (message.StringProperties && message.StringProperties[condition.column] && condition.regex.test(message.StringProperties[condition.column]));
}
});
return matched;
});
}
}
function evalMessage(message, regex) {
var jmsHeaders = ['JMSDestination', 'JMSDeliveryMode', 'JMSExpiration', 'JMSPriority', 'JMSmessageID', 'JMSTimestamp', 'JMSCorrelationID', 'JMSReplyTo', 'JMSType', 'JMSRedelivered'];
for (var i = 0; i < jmsHeaders.length; i++) {
var header = jmsHeaders[i];
if (message[header] && regex.test(message[header])) {
return true;
}
}
if (message.StringProperties) {
for ( var property in message.StringProperties) {
if (regex.test(message.StringProperties[property])) {
return true;
}
}
}
if (message.bodyText && regex.test(message.bodyText)) {
return true;
}
return false;
}
function getRegExp(str, modifiers) {
try {
return new RegExp(str, modifiers);
} catch (err) {
return new RegExp(str.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\\|\||\.|\*|\+|\?)/g, '\\$1'));
}
}
function buildSearchConditions(filterText) {
var searchConditions = [];
var qStr;
if (!(qStr = $.trim(filterText))) {
return;
}
var columnFilters = qStr.split(";");
for (var i = 0; i < columnFilters.length; i++) {
var args = columnFilters[i].split(':');
if (args.length > 1) {
var columnName = $.trim(args[0]);
var columnValue = $.trim(args[1]);
if (columnName && columnValue) {
searchConditions.push({
column: columnName,
columnDisplay: columnName.replace(/\s+/g, '').toLowerCase(),
regex: getRegExp(columnValue, 'i')
});
}
} else {
var val = $.trim(args[0]);
if (val) {
searchConditions.push({
column: '',
regex: getRegExp(val, 'i')
});
}
}
}
return searchConditions;
}
function afterSelectionChange(rowItem, checkAll) {
if (checkAll === void 0) {
// then row was clicked, not select-all checkbox
$scope.gridOptions['$gridScope'].allSelected = rowItem.config.selectedItems.length == $scope.messages.length;
} else {
$scope.gridOptions['$gridScope'].allSelected = checkAll;
}
}
function deselectAll() {
$scope.gridOptions['$gridScope'].allSelected = false;
}
}
return ARTEMIS;
}(ARTEMIS || {}));

View File

@ -0,0 +1,217 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
//Artemis.log.info("loading addresses");
Artemis._module.component('artemisAddresses', {
template:
`<h1>Browse Addresses
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'addresses-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
items="$ctrl.addresses">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<script type="text/ng-template" id="addresses-instructions.html">
<div>
<p>
This page allows you to browse all address on the broker. These can be narrowed down
by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
click on the <span class="fa fa-search"></span> button.
</p>
<p>
You can also navigate directly to the JMX attributes and operations tabs by using the <code>attributes</code>
and <code>operations</code> button under the <code>Actions</code> column.You can navigate to the
addresses queues by clicking on the <code>Queue Count</code> field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: AddressesController
})
.name;
function AddressesController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisAddress) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allAddresses = [];
ctrl.addresses = [];
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'NAME', name: 'Name'},
{id: 'ROUTING_TYPES', name: 'Queue Count'},
{id: 'QUEUE_COUNT', name: 'User'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "id"
},
text: {
fieldText: "Filter Field..",
operationText: "Operation..",
sortOrderText: "ascending",
sortByText: "ID"
}
};
ctrl.tableActionButtons = [
{
name: 'attributes',
title: 'Navigate to attributes',
actionFn: navigateToAddressAtts
},
{
name: 'operations',
title: 'navigate to operations',
actionFn: navigateToAddressOps
}
];
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'id' },
{ header: 'Name', itemField: 'name' },
{ header: 'Routing Types', itemField: 'routingTypes' },
{ header: 'Queue Count', itemField: 'queueCount' , templateFn: function(value, item) { return '<a href="#" onclick="selectQueues(\'' + item.name + '\')">' + value + '</a>' }}
];
ctrl.refresh = function () {
ctrl.refreshed = true;
ctrl.pagination.load();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "id";
ctrl.refreshed = true;
artemisAddress.address = null;
ctrl.pagination.load();
};
if (artemisAddress.address) {
Artemis.log.info("navigating to address = " + artemisAddress.address.address);
ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisAddress.address.address;
}
selectQueues = function (address) {
Artemis.log.info("navigating to queues:" + address)
artemisAddress.address = { address: address };
$location.path("artemis/artemisQueues");
};
function navigateToAddressAtts(action, item) {
$location.path("artemis/attributes").search({"tab": "artemis", "nid": getAddressNid(item.name, $location)});
};
function navigateToAddressOps(action, item) {
$location.path("artemis/operations").search({"tab": "artemis", "nid": getAddressNid(item.name, $location)});
};
function getAddressNid(address, $location) {
var rootNID = getRootNid($location);
var targetNID = rootNID + "addresses-" + address;
Artemis.log.info("targetNID=" + targetNID);
return targetNID;
}
function getRootNid($location) {
var currentNid = $location.search()['nid'];
Artemis.log.info("current nid=" + currentNid);
var firstDash = currentNid.indexOf('-');
var secondDash = currentNid.indexOf('-', firstDash + 1);
var thirdDash = currentNid.indexOf('-', secondDash + 1);
if (thirdDash < 0) {
return currentNid + "-";
}
var rootNID = currentNid.substring(0, thirdDash + 1);
return rootNID;
}
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listAddresses(java.lang.String, int, int)';
var addressFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(addressFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
ctrl.pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list sessions" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.addresses = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.addresses.push(value);
});
ctrl.pagination.page(data["count"]);
allAddresses = ctrl.addresses;
ctrl.addresses = allAddresses;
Core.$apply($scope);
}
ctrl.pagination.load();
}
AddressesController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisAddress'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,849 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisBrowseQueue', {
template:
`<h1>Browse Queue
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'browse-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div class="table-view artemis-browse-main" ng-show="!$ctrl.showMessageDetails">
<div class="row toolbar-pf table-view-pf-toolbar" id="toolbar1">
<div class="col-sm-20">
<form class="toolbar-pf-actions">
<div class="form-group toolbar-pf-filter">
<div class="input-group">
<input type="text" class="form-control" ng-model="$ctrl.filter.values.value" placeholder="Filter..." autocomplete="off" id="filterInput">
<div class="input-group-btn">
<button class="btn btn-link btn-find" ng-click="$ctrl.refresh()" type="button">
&nbsp;&nbsp;<span class="fa fa-search"></span>&nbsp;&nbsp;
</button>
</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-click="$ctrl.reset()">Reset
</button>
<button class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-disabled="$ctrl.deleteDisabled"
ng-click="$ctrl.openDeleteDialog()">Delete Messages
</button>
<button class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-disabled="$ctrl.moveDisabled"
ng-click="$ctrl.openMoveDialog()">Move Messages
</button>
<button ng-show="$ctrl.dlq" class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-disabled="$ctrl.retryDisabled"
ng-click="$ctrl.openRetryDialog()">Retry Messages
</button>
</div>
</form>
</div>
</div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
items="$ctrl.messages"
dt-options="$ctrl.tableDtOptions"
action-buttons="$ctrl.tableMenuActions">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
</div>
<div class="form-group" ng-show="$ctrl.showMessageDetails">
<button class="btn btn-primary" ng-click="$ctrl.showMessageDetails = false">Back</button>
<h2>MessageID: {{$ctrl.currentMessage.messageID}}</h2>
<h2>Headers</h2>
<pf-toolbar config="$ctrl.messageToolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.messageTableConfig"
columns="$ctrl.messageTableColumns"
items="$ctrl.currentMessage.headers">
</pf-table-view>
<h2>Properties</h2>
<div ng-show="$ctrl.showMessageDetails">
<pf-toolbar config="$ctrl.messagePToolbarConfig"></pf-toolbar>
<pf-table-view config="$ctrl.messagePTableConfig"
columns="$ctrl.messageTableColumns"
items="$ctrl.currentMessage.properties">
</pf-table-view>
</div>
<h3>Displaying body as <span ng-bind="$ctrl.currentMessage.textMode"></span></h3>
<div hawtio-editor="$ctrl.currentMessage.bodyText" read-only="true" mode='mode'></div>
</div>
<div hawtio-confirm-dialog="$ctrl.deleteDialog" title="Delete messages?"
ok-button-text="Delete"
cancel-button-text="Cancel"
on-ok="$ctrl.deleteMessages()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
This operation cannot be undone so please be careful.
</p>
<p>{{$ctrl.actionText}}</p>
</div>
</div>
<div hawtio-confirm-dialog="$ctrl.moveDialog" title="Move messages?"
ok-button-text="Move"
cancel-button-text="Cancel"
on-ok="$ctrl.moveMessages()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
You cannot undo this operation.<br/>
Though after the move you can always move them back again.
</p>
<p>{{$ctrl.actionText}}</p>
<p>Move
<ng-pluralize count="$filter('filter')(ctrl.messages, {selected: true}).length"
when="{'1': 'message', 'other': '{} messages'}"></ng-pluralize>
to: <select ng-model="$ctrl.queueName" ng-options="qn for qn in $ctrl.queueNames" ng-init="queueName=$ctrl.queueNames[0]"></select>
</p>
</div>
</div>
<div hawtio-confirm-dialog="$ctrl.retryDialog" title="Retry messages?"
ok-button-text="Retry"
cancel-button-text="Cancel"
on-ok="$ctrl.retryMessages()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
You cannot undo this operation.<br/>
Though after the move you can always move them back again.
</p>
<p>{{$ctrl.actionText}}</p>
</div>
</div>
<script type="text/ng-template" id="browse-instructions.html">
<div>
<p>
This page allows you to browse messages on a queue in Artemis. Messages are loaded in from the broker
a page at a time and can be filtered at the broker using the <code>filter</code>: see <a href="https://activemq.apache.org/components/artemis/documentation/latest/filter-expressions.html" target="_blank">Filter Expressions</a>
. To execute a query click on the <span class="fa fa-search"></span> button.
</p>
<p>
Clicking on the <code>show</code> buton will show the messages details in more detail including, headers, properties
and the body if viewable. Clicking on the <code>resend</code> button will navigate to the <code>Send Message</code>
tab and copy the message details so a copy of the message can be resent.
</p>
</div>
</script>
`,
controller: BrowseQueueController
})
.name;
function BrowseQueueController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination) {
var ctrl = this;
ctrl.dlq = false;
ctrl.deleteDisabled = true;
ctrl.moveDisabled = true;
ctrl.retryDisabled = true;
ctrl.pagination = pagination;
ctrl.filter = '';
ctrl.actionText = '';
ctrl.allMessages = [];
ctrl.messages = [];
var objName;
if (workspace.selection) {
objName = workspace.selection.objectName;
} else {
// in case of refresh
var key = location.search()['nid'];
var node = workspace.keyToNodeMap[key];
objName = node.objectName;
}
var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
Artemis.log.debug("loading table" + artemisExpiryQueue);
if (objName) {
ctrl.dlq = false;
var queueName = jolokia.getAttribute(objName, "Name");
if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
ctrl.dlq = true;
}
}
ctrl.tableConfig = {
onCheckBoxChange: handleCheckBoxChange,
selectionMatchProp: 'messageID',
showCheckboxes: true
};
ctrl.tableColumns = [
{
itemField: 'messageID',
header: 'messageID'
},
{
itemField: 'type',
header: 'Type',
templateFn: function(value) {
return formatType(value);
}
},
{
itemField: 'durable',
header: 'Durable'
},
{
itemField: 'priority',
header: 'Priority'
},
{
itemField: 'timestamp',
header: 'Timestamp',
templateFn: function(value) {
return formatTimestamp(value);
}
},
{
itemField: 'expiration',
header: 'Expires',
templateFn: function(value) {
return formatExpires(value);
}
},
{
header: 'Redelivered',
itemField: 'redelivered'
},
{
itemField: 'largeMessage',
header: 'Large'
},
{
itemField: 'persistentSize',
header: 'Persistent Size',
templateFn: function(value) {
return formatPersistentSize(value);
}
},
{
itemField: 'userID',
header: 'User ID'
},
{
itemField: 'StringProperties',
header: 'Validated User',
templateFn: function(value) {
return value._AMQ_VALIDATED_USER;
}
}
];
var resendConfig = {
name: 'Resend',
title: 'Resend message',
actionFn: resendMessage
};
var showConfig = {
name: 'Show',
title: 'Show message',
actionFn: openMessageDialog
};
ctrl.messageTableConfig = { selectionMatchProp: 'key', itemsAvailable: true, showCheckboxes: false };
ctrl.messagePTableConfig = { selectionMatchProp: 'key', itemsAvailable: true, showCheckboxes: false };
ctrl.messageToolbarConfig = {
isTableView: true
};
ctrl.messagePToolbarConfig = {
isTableView: true
};
ctrl.messageTableColumns = [
{
itemField: 'key',
header: 'key'
},
{
itemField: 'value',
header: 'value'
}];
ctrl.tableMenuActions = [ showConfig, resendConfig ];
ctrl.tableDtOptions = {
order: [[0, "asc"]]
};
ctrl.sysprops = [];
Artemis.log.debug("loaded browse 5" + Artemis.browseQueueModule);
ctrl.currentMessage;
ctrl.queueNames = [];
ctrl.queueName = '';
ctrl.resultSizeDialog = false;
//success message
ctrl.message = '';
//error message
ctrl.errorMessage = '';
$scope.mode = 'text';
ctrl.deleteDialog = false;
ctrl.moveDialog = false;
ctrl.retryDialog = false;
ctrl.showMessageDetails = false;
var ignoreColumns = ["PropertiesText", "bodyText", "BodyPreview", "text", "headers", "properties", "textMode"];
var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"];
function openMessageDialog(action, item) {
ctrl.currentMessage = item;
ctrl.currentMessage.headers = createHeaders(ctrl.currentMessage)
ctrl.currentMessage.properties = createProperties(ctrl.currentMessage);
ctrl.currentMessage.bodyText = createBodyText(ctrl.currentMessage);
ctrl.showMessageDetails = true;
};
var MS_PER_SEC = 1000;
var MS_PER_MIN = 60 * MS_PER_SEC;
var MS_PER_HOUR = 60 * MS_PER_MIN;
var MS_PER_DAY = 24 * MS_PER_HOUR;
function pad2(value) {
return (value < 10 ? '0' : '') + value;
}
function formatExpires(timestamp) {
if (isNaN(timestamp)) {
return timestamp;
}
var expiresIn = timestamp - Date.now();
if (Math.abs(expiresIn) < MS_PER_DAY) {
var duration = expiresIn < 0 ? -expiresIn : expiresIn;
var hours = pad2(Math.floor((duration / MS_PER_HOUR) % 24));
var mins = pad2(Math.floor((duration / MS_PER_MIN) % 60));
var secs = pad2(Math.floor((duration / MS_PER_SEC) % 60));
if (expiresIn < 0) {
// "HH:mm:ss ago"
return hours + ":" + mins + ":" + secs + " ago";
}
// "in HH:mm:ss ago"
return "in " + hours + ":" + mins + ":" + secs;
}
return formatTimestamp(timestamp);
}
function formatTimestamp(timestamp) {
if (isNaN(timestamp)) {
return timestamp;
}
var d = new Date(timestamp);
// "yyyy-MM-dd HH:mm:ss"
return d.getFullYear() + "-" + pad2(d.getMonth()) + "-" + pad2(d.getDay()) + " " + pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
}
var typeLabels = ["default", "1", "object", "text", "bytes", "map", "stream", "embedded"];
function formatType(type) {
if (isNaN(type)) {
return type;
}
return type > -1 && type < 8 ? typeLabels[type] : type
}
ctrl.refresh = function() {
Artemis.log.info(ctrl.filter)
ctrl.pagination.load();
}
ctrl.reset = function() {
ctrl.filter = '';
ctrl.pagination.load();
}
function formatPersistentSize(bytes) {
if(isNaN(bytes) || bytes < 0) return "n/a";
if(bytes < 10240) return bytes.toLocaleString() + " Bytes";
if(bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
if(bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
return (bytes / 1073741824).toFixed(2) + " GB";
}
ctrl.openMoveDialog = function () {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
if(!selectedItems) {
return;
}
ctrl.actionText = "You are about to move " + Core.maybePlural(selectedItems.length, "message");
Artemis.log.debug(ctrl.actionText);
ctrl.moveDialog = true;
};
ctrl.moveMessages = function (action, item) {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
if(!selectedItems) {
selectedItems = [];
return;
}
ctrl.message = "Moved " + Core.maybePlural(selectedItems.length, "message" + " to " + ctrl.queueName);
ctrl.errorMessage = "failed to move message";
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : moveSuccess;
jolokia.execute(mbean, "moveMessage(long,java.lang.String)", id, ctrl.queueName, Core.onSuccess(callback, { error: onError }));
}
});
}
};
function resendMessage(action, item) {
// always assume a single message
artemisMessage.message = item;
$location.path('artemis/artemisSendMessage');
};
function onError(response) {
Core.notification("error", ctrl.errorMessage + response.error);
}
function handleCheckBoxChange (item) {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
Artemis.log.debug("sel " + selectedItems.length);
if (selectedItems.length == 0) {
ctrl.deleteDisabled = true;
ctrl.moveDisabled = true;
ctrl.retryDisabled = true;
return;
}
ctrl.deleteDisabled = false;
ctrl.moveDisabled = false;
ctrl.retryDisabled = false;
}
ctrl.openDeleteDialog = function () {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
if(!selectedItems) {
selectedItems = [];
return;
}
ctrl.actionText = "You are about to delete " + Core.maybePlural(selectedItems.length, "message");
Artemis.log.debug(ctrl.actionText);
ctrl.deleteDialog = true;
}
ctrl.deleteMessages = function () {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $filter('filter')(ctrl.allMessages, {selected: true});
if(!selectedItems) {
selectedItems = [];
return;
}
ctrl.message = "Deleted " + Core.maybePlural(selectedItems.length, "message");
ctrl.errorMessage = "failed to delete message";
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
jolokia.execute(mbean, "removeMessage(long)", id, Core.onSuccess(callback, { error: onError }));
}
});
}
};
ctrl.openRetryDialog = function () {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
if(!selectedItems) {
return;
}
ctrl.actionText = "You are about to retry " + Core.maybePlural(selectedItems.length, "message");
Artemis.log.debug(ctrl.actionText);
ctrl.retryDialog = true;
};
ctrl.retryMessages = function() {
var selection = workspace.selection;
var mbean = selection.objectName;
if (mbean && selection) {
var selectedItems = $filter('filter')(ctrl.messages, {selected: true});
ctrl.message = "Retry " + Core.maybePlural(selectedItems.length, "message");
ctrl.errorMessage = "failed to retry message";
angular.forEach(selectedItems, function(item, idx) {
var id = item.messageID;
if (id) {
var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess;
jolokia.execute(mbean, "retryMessage(long)", id, Core.onSuccess(callback, { error: onError }));
}
});
}
};
function populateTable(response) {
Artemis.log.debug("loading data:" + data);
if (ctrl.queueNames.length === 0) {
var queueNames = getSelectionQueuesFolder(workspace);
var selectedQueue = workspace.selection.text;
ctrl.queueNames = queueNames.filter(function (name) { return name !== selectedQueue; });
}
var data = response.value;
if (!angular.isArray(data)) {
ctrl.allMessages = [];
angular.forEach(data, function(value, idx) {
ctrl.allMessages.push(value);
})
} else {
ctrl.allMessages = data;
}
angular.forEach(ctrl.allMessages, function(message) {
message.bodyText = createBodyText(message);
});
ctrl.messages = ctrl.allMessages;
ctrl.isLoading = false;
Core.$apply($scope);
}
function findFolder(node) {
if (!node) {
return null;
}
var answer = [];
var addresses = node.children;
angular.forEach(addresses, function (address) {
var subQueues = address.children;
angular.forEach(subQueues, function (subQueue) {
var routingTypes = subQueue.children;
angular.forEach(routingTypes, function (routingType) {
var queues = routingType.children;
angular.forEach(queues, function (queue) {
answer.push(queue.title);
});
});
});
});
return answer;
}
function findAddressesNode(node) {
if (!node) {
return null;
}
if (node.title === "addresses") {
return node;
}
if (node.title == Artemis.jmxDomain) {
return null;
}
return findAddressesNode(node.parent);
}
function getSelectionQueuesFolder(workspace) {
var selection = workspace.selection;
var addressesNode = findAddressesNode(selection);
var queueFolder = selection ? findFolder(addressesNode) : null;
return queueFolder;
}
/*
* For some reason using ng-repeat in the modal dialog doesn't work so lets
* just create the HTML in code :)
*/
function createBodyText(message) {
Artemis.log.debug("loading message:" + message);
if (message.text) {
var body = message.text;
var lenTxt = "" + body.length;
message.textMode = "text (" + lenTxt + " chars)";
return body;
} else if (message.BodyPreview) {
var code = Core.parseIntValue(localStorage["ArtemisBrowseBytesMessages"] || "1", "browse bytes messages");
var body;
message.textMode = "bytes (turned off)";
if (code != 99) {
var bytesArr = [];
var textArr = [];
message.BodyPreview.forEach(function(b) {
if (code === 1 || code === 2) {
// text
textArr.push(String.fromCharCode(b));
}
if (code === 1 || code === 4) {
// hex and must be 2 digit so they space out evenly
var s = b.toString(16);
if (s.length === 1) {
s = "0" + s;
}
bytesArr.push(s);
} else {
// just show as is without spacing out, as that is usually more used for hex than decimal
var s = b.toString(10);
bytesArr.push(s);
}
});
var bytesData = bytesArr.join(" ");
var textData = textArr.join("");
if (code === 1 || code === 2) {
// bytes and text
var len = message.BodyPreview.length;
var lenTxt = "" + textArr.length;
body = "bytes:\n" + bytesData + "\n\ntext:\n" + textData;
message.textMode = "bytes (" + len + " bytes) and text (" + lenTxt + " chars)";
} else {
// bytes only
var len = message.BodyPreview.length;
body = bytesData;
message.textMode = "bytes (" + len + " bytes)";
}
}
return body;
} else {
message.textMode = "unsupported";
return "Unsupported message body type which cannot be displayed by hawtio";
}
}
function createHeaders(message) {
var headers = [];
angular.forEach(message, function (value, key) {
if (!_.some(ignoreColumns, function (k) { return k === key; }) && !_.some(flattenColumns, function (k) { return k === key; })) {
headers.push({key: key, value: value});
}
});
return headers;
}
function createProperties(message) {
var properties = [];
angular.forEach(message, function (value, key) {
if (!_.some(ignoreColumns, function (k) { return k === key; }) && _.some(flattenColumns, function (k) { return k === key; })) {
Artemis.log.debug("key=" + key + " value=" + value);
angular.forEach(value, function (v2, k2) {
Artemis.log.debug("key=" + k2 + " value=" + v2);
properties.push({key: k2, value: v2});
});
}
});
return properties;
}
ctrl.loadTable = function() {
Artemis.log.debug("loading table")
ctrl.isLoading = true;
var objName;
if (workspace.selection) {
objName = workspace.selection.objectName;
} else {
// in case of refresh
var key = location.search()['nid'];
var node = workspace.keyToNodeMap[key];
objName = node.objectName;
}
if (objName) {
ctrl.dlq = false;
var queueName = jolokia.getAttribute(objName, "Name");
var artemisDLQ = localStorage['artemisDLQ'] || "DLQ";
var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue";
Artemis.log.debug("loading table" + artemisExpiryQueue);
if (queueName == artemisDLQ || queueName == artemisExpiryQueue) {
onDlq(true);
} else {
onDlq(false);
}
jolokia.request({ type: 'exec', mbean: objName, operation: 'countMessages()'}, Core.onSuccess(function(response) { ctrl.pagination.page(response.value); }));
jolokia.request({ type: 'exec', mbean: objName, operation: 'browse(int, int, java.lang.String)', arguments: [ctrl.pagination.pageNumber, ctrl.pagination.pageSize, ctrl.filter] }, Core.onSuccess(populateTable));
}
}
function onDlq(response) {
Artemis.log.debug("onDLQ=" + response);
ctrl.dlq = response;
Core.$apply($scope);
}
function operationSuccess() {
ctrl.messageDialog = false;
Core.notification("success", ctrl.message);
ctrl.pagination.load();
}
function intermediateResult() {
}
function moveSuccess() {
operationSuccess();
workspace.loadTree();
}
function filterMessages(filter) {
var searchConditions = buildSearchConditions(filter);
evalFilter(searchConditions);
}
function applyFilters(filters) {
Artemis.log.debug("filters " + filters);
ctrl.messages = [];
if (filters && filters.length > 0) {
ctrl.allMessages.forEach(function (message) {
if (matchesFilters(message, filters)) {
ctrl.messages.push(message);
}
});
} else {
ctrl.messages = ctrl.allMessages;
}
};
var matchesFilter = function (message, filter) {
var match = true;
if (filter.id === 'messageID') {
match = message.messageID.match(filter.value) !== null;
} else if (filter.id === 'body') {
match = message.bodyText.match(filter.value) !== null;
} else if (filter.id === 'properties') {
match = message.PropertiesText.match(filter.value) !== null;
} else if (filter.id === 'priority') {
match = message.priority == filter.value;
} else if (filter.id === 'redelivered') {
var filterTrue = filter.value == 'true';
match = (message.redelivered == filterTrue);
}
return match;
};
var matchesFilters = function (message, filters) {
var matches = true;
filters.forEach(function(filter) {
Artemis.log.debug("filter " + filter.id);
if (!matchesFilter(message, filter)) {
matches = false;
return false;
}
});
return matches;
};
function evalFilter(searchConditions) {
if (!searchConditions || searchConditions.length === 0) {
$scope.messages = ctrl.allMessages;
} else {
Artemis.log.debug("Filtering conditions:", searchConditions);
$scope.messages = ctrl.allMessages.filter(function(message) {
Artemis.log.debug("Message:", message);
var matched = true;
$.each(searchConditions, function(index, condition) {
if (!condition.column) {
matched = matched && evalMessage(message, condition.regex);
} else {
matched = matched && (message[condition.column] && condition.regex.test(message[condition.column])) || (message.StringProperties && message.StringProperties[condition.column] && condition.regex.test(message.StringProperties[condition.column]));
}
});
return matched;
});
}
}
function evalMessage(message, regex) {
var jmsHeaders = ['JMSDestination', 'JMSDeliveryMode', 'JMSExpiration', 'JMSPriority', 'JMSmessageID', 'JMSTimestamp', 'JMSCorrelationID', 'JMSReplyTo', 'JMSType', 'JMSRedelivered'];
for (var i = 0; i < jmsHeaders.length; i++) {
var header = jmsHeaders[i];
if (message[header] && regex.test(message[header])) {
return true;
}
}
if (message.StringProperties) {
for ( var property in message.StringProperties) {
if (regex.test(message.StringProperties[property])) {
return true;
}
}
}
if (message.bodyText && regex.test(message.bodyText)) {
return true;
}
return false;
}
function getRegExp(str, modifiers) {
try {
return new RegExp(str, modifiers);
} catch (err) {
return new RegExp(str.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\\|\||\.|\*|\+|\?)/g, '\\$1'));
}
}
function buildSearchConditions(filterText) {
var searchConditions = [];
var qStr;
if (!(qStr = $.trim(filterText))) {
return;
}
var columnFilters = qStr.split(";");
for (var i = 0; i < columnFilters.length; i++) {
var args = columnFilters[i].split(':');
if (args.length > 1) {
var columnName = $.trim(args[0]);
var columnValue = $.trim(args[1]);
if (columnName && columnValue) {
searchConditions.push({
column: columnName,
columnDisplay: columnName.replace(/\s+/g, '').toLowerCase(),
regex: getRegExp(columnValue, 'i')
});
}
} else {
var val = $.trim(args[0]);
if (val) {
searchConditions.push({
column: '',
regex: getRegExp(val, 'i')
});
}
}
}
return searchConditions;
}
ctrl.pagination.setOperation(ctrl.loadTable);
ctrl.pagination.load();
}
BrowseQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination'];
})(Artemis || (Artemis = {}));

View File

@ -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.
*/
var Artemis;
(function (Artemis) {
Artemis.log.info("loading connections");
Artemis._module.component('artemisConnections', {
template:
`
<h1>Browse Connections
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'connections-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
items="$ctrl.connections">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Connection?"
ok-button-text="Close"
cancel-button-text="Cancel"
on-ok="$ctrl.closeConnection()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
You are about to close the selected connection: {{$ctrl.connectionToDelete}}
<p>Are you sure you want to continue.</p>
</p>
</div>
</div>
<script type="text/ng-template" id="connections-instructions.html">
<div>
<p>
This page allows you to browse all connections currently connected to the broker, including client, cluster
and bridge connections. These can be narrowed down by specifying a filter and also sorted using the sort
function in the toolbar. To execute a query click on the <span class="fa fa-search"></span> button.
</p>
<p>
Connections can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
navigate to the connections sessions open by clicking on the <code>Session Count</code> field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: ConnectionsController
})
.name;
function ConnectionsController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConnection, artemisSession) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allConnections = [];
ctrl.connections = [];
ctrl.pageNumber = 1;
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.connectionToDelete = '';
ctrl.closeDialog = false;
ctrl.filter = {
fieldOptions: [
{id: 'CONNECTION_ID', name: 'ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USERS', name: 'Users'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'SESSION_COUNT', name: 'Session Count'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'SESSION_ID', name: 'Session ID'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "connectionID"
}
};
ctrl.tableActionButtons = [
{
name: 'Close',
title: 'Close the Connection',
actionFn: openCloseDialog
}
];
ctrl.tableConfig = {
selectionMatchProp: 'connectionID',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'connectionID' },
{ header: 'Client ID', itemField: 'clientID' },
{ header: 'Users', itemField: 'users' },
{ header: 'protocol', itemField: 'protocol' },
{ header: 'Session Count', itemField: 'sessionCount', templateFn: function(value, item) { return '<a href="#" onclick="selectSessions(\'' + item.connectionID + '\')">' + value + '</a>' }},
{ header: 'Remote Address', itemField: 'remoteAddress' },
{ header: 'Local Address', itemField: 'localAddress' },
{ header: 'Creation Time', itemField: 'creationTime' }
];
selectSessions = function (connection) {
Artemis.log.info("navigating to connection:" + connection)
artemisConnection.connection = { connectionID: connection };
$location.path("artemis/artemisSessions");
};
if (artemisSession.session) {
Artemis.log.info("navigating to session = " + artemisSession.session.connectionID);
ctrl.filter.values.field = ctrl.filter.fieldOptions[0].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisSession.session.connectionID;
}
ctrl.refresh = function () {
ctrl.refreshed = true;
ctrl.pagination.load();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "connectionID";
ctrl.filter.text.fieldText = "Filter Field..";
ctrl.filter.text.operationText = "Operation..";
ctrl.filter.text.sortOrderText = "ascending";
ctrl.filter.text.sortByText = "ID";
ctrl.refreshed = true;
artemisSession.session = null;
ctrl.pagination.load();
};
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listConnections(java.lang.String, int, int)';
var connectionsFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
Artemis.log.info(JSON.stringify(connectionsFilter));
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(connectionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
function openCloseDialog(action, item) {
ctrl.connectionToDelete = item.connectionID;
ctrl.closeDialog = true;
}
ctrl.closeConnection = function () {
Artemis.log.info("closing connection: " + ctrl.connectionToDelete);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeConnectionWithID(java.lang.String)',
arguments: [ctrl.connectionToDelete] },
Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close connection: " + response);
}}));
}
};
pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list connections" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.connections = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.connections.push(value);
});
ctrl.pagination.page(data["count"]);
allConnections = ctrl.connections;
ctrl.connections = allConnections;
Core.$apply($scope);
}
ctrl.pagination.load();
}
ConnectionsController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConnection', 'artemisSession'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,248 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisConsumers', {
template:
`<h1>Browse Consumers
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'consumers-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
items="$ctrl.consumers">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Consumer?"
ok-button-text="Close"
cancel-button-text="Cancel"
on-ok="$ctrl.closeConsumer()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
You are about to close the selected consumer: {{$ctrl.consumerToDelete}}
<p>Are you sure you want to continue.</p>
</p>
</div>
</div>
<script type="text/ng-template" id="consumers-instructions.html">
<div>
<p>
This page allows you to browse all consumers currently open on the broker. These can be narrowed down
by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
click on the <span class="fa fa-search"></span> button.
</p>
<p>
Consumers can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
navigate to the consumers session, address and queue by clicking on the appropriate field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: ConsumersController
})
.name;
function ConsumersController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConsumer, artemisQueue, artemisAddress, artemisSession) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allConsumers = [];
ctrl.consumers = [];
ctrl.pageNumber = 1;
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.consumerToDeletesSession = '';
ctrl.consumerToDelete = '';
ctrl.closeDialog = false;
ctrl.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'SESSION_ID', name: 'Session ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USER', name: 'User'},
{id: 'ADDRESS', name: 'Address'},
{id: 'QUEUE', name: 'Queue'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "id"
},
text: {
fieldText: "Filter Field..",
operationText: "Operation..",
sortOrderText: "ascending",
sortByText: "ID"
}
};
ctrl.tableActionButtons = [
{
name: 'Close',
title: 'Close the Consumer',
actionFn: openCloseDialog
}
];
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'id' },
{ header: 'Session', itemField: 'session' , templateFn: function(value, item) { return '<a href="#" onclick="selectSession(\'' + item.session + '\')">' + value + '</a>' }},
{ header: 'Client ID', itemField: 'clientID' },
{ header: 'Protocol', itemField: 'protocol' },
{ header: 'Queue', itemField: 'queue', templateFn: function(value, item) { return '<a href="#" onclick="selectQueue(\'' + item.queue + '\')">' + value + '</a>' }},
{ header: 'queueType', itemField: 'queueType' },
{ header: 'Filter', itemField: 'filter' },
{ header: 'Address', itemField: 'address' , templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
{ header: 'Remote Address', itemField: 'remoteAddress' },
{ header: 'Local Address', itemField: 'localAddress' },
{ header: 'Creation Time', itemField: 'creationTime' }
];
ctrl.refresh = function () {
ctrl.refreshed = true;
ctrl.pagination.load();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "id";
ctrl.filter.text.fieldText = "Filter Field..";
ctrl.filter.text.operationText = "Operation..";
ctrl.filter.text.sortOrderText = "ascending";
ctrl.filter.text.sortByText = "ID";
ctrl.refreshed = true;
artemisConsumer.consumer = null;
ctrl.pagination.load();
};
if (artemisConsumer.consumer) {
Artemis.log.info("navigating to consumer = " + artemisConsumer.consumer.sessionID);
ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisConsumer.consumer.sessionID;
}
selectQueue = function (queue) {
Artemis.log.info("navigating to queue:" + queue)
artemisQueue.queue = { queue: queue };
$location.path("artemis/artemisQueues");
};
selectAddress = function (address) {
Artemis.log.info("navigating to address:" + address)
artemisAddress.address = { address: address };
$location.path("artemis/artemisAddresses");
};
selectSession = function (session) {
Artemis.log.info("navigating to session:" + session)
artemisSession.session = { session: session };
$location.path("artemis/artemisSessions");
};
function openCloseDialog(action, item) {
ctrl.consumerToDelete = item.id;
ctrl.consumerToDeletesSession = item.session;
ctrl.closeDialog = true;
}
ctrl.closeConsumer = function () {
Artemis.log.info("closing session: " + ctrl.consumerToDelete);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeConsumerWithID(java.lang.String,java.lang.String)',
arguments: [ctrl.consumerToDeletesSession, ctrl.consumerToDelete] },
Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close session: " + response);
}}));
}
};
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listConsumers(java.lang.String, int, int)';
var sessionsFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(sessionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
ctrl.pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list sessions" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.consumers = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.consumers.push(value);
});
ctrl.pagination.page(data["count"]);
allConsumers = ctrl.consumers;
ctrl.consumers = allConsumers;
Core.$apply($scope);
}
ctrl.pagination.load();
}
ConsumersController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConsumer', 'artemisQueue', 'artemisAddress', 'artemisSession'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,139 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisCreateAddress', {
template:
`
<h1>Create Address
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'create-address-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="name-markup">Address name</label>
<div class="col-sm-10">
<input id="name-markup" class="form-control" type="text" maxlength="300"
name="addressName" ng-model="$ctrl.addressName" placeholder="Address name"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Routing type</label>
<div class="col-sm-10">
<label class="checkbox">
<input type="radio" ng-model="$ctrl.routingType" value="Multicast"> Multicast
</label>
<label class="checkbox">
<input type="radio" ng-model="$ctrl.routingType" value="Anycast"> Anycast
</label>
<label class="checkbox">
<input type="radio" ng-model="$ctrl.routingType" value="Both"> Both
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary"
ng-click="$ctrl.createAddress($ctrl.addressName, $ctrl.routingType)"
ng-disabled="!$ctrl.addressName">Create Address
</button>
</div>
</div>
<div hawtio-confirm-dialog="$ctrl.createDialog"
ok-button-text="Create"
cancel-button-text="Cancel"
on-ok="$ctrl.createAddress($ctrl.addressName, $ctrl.routingType)">
<div class="dialog-body">
<p>Address name <b>{{$ctrl.addressName}}</b> contains unrecommended characters: <code>:</code></p>
<p>This may cause unexpected problems. Are you really sure to create this {{$ctrl.uncapitalisedDestinationType()}}?</p>
</div>
</div>
</form>
<script type="text/ng-template" id="create-address-instructions.html">
<div>
<p>
This page allows you to create a new address on the broker, if you want the address to support JMS like
queues, i.e. point to point, then choose anycast. If you want your address to support JMS like topic
subscriptions, publish/subscribe, then choose multicast.
</p>
</div>
</script>
`,
controller: CreateAddressController
})
.name;
Artemis.log.info("loaded address " + Artemis.addressModule);
function CreateAddressController($scope, workspace, jolokia, localStorage) {
Artemis.log.info("loaded address controller");
var ctrl = this;
ctrl.addressName = "";
ctrl.routingType = "Anycast";
ctrl.workspace = workspace;
ctrl.message = "";
$scope.$watch('workspace.selection', function () {
workspace.moveIfViewInvalid();
});
function operationSuccess() {
ctrl.addressName = "";
ctrl.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
ctrl.workspace.loadTree();
}
function onError(response) {
Core.notification("error", "Could not create address: " + response.error);
}
ctrl.createAddress = function (name, routingType) {
Artemis.log.info("creating " + routingType);
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
if (mbean) {
if (routingType == "Multicast") {
$scope.message = "Created Multicast Address " + name;
Artemis.log.info(ctrl.message);
jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "MULTICAST", Core.onSuccess(operationSuccess, { error: onError }));
}
else if (routingType == "Anycast") {
$scope.message = "Created Anycast Address " + name;
Artemis.log.info(ctrl.message);
jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "ANYCAST", Core.onSuccess(operationSuccess, { error: onError }));
}
else {
$scope.message = "Created Anycast/Multicast Address " + name;
Artemis.log.info(ctrl.message);
jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, "ANYCAST,MULTICAST", Core.onSuccess(operationSuccess, { error: onError }));
}
}
};
}
CreateAddressController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,206 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisCreateQueue', {
template:
`
<h1>Create Queue
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'create-queue-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="name-markup">Queue name</label>
<div class="col-sm-10">
<input id="name-markup" class="form-control" type="text" maxlength="300"
name="queueName" ng-model="$ctrl.queueName" placeholder="Queue name"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Routing type</label>
<div class="col-sm-10">
<label class="checkbox">
<input type="radio" ng-model="$ctrl.routingType" value="Anycast"> Anycast
</label>
<label class="checkbox">
<input type="radio" ng-model="$ctrl.routingType" value="Multicast"> Multicast
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Durable</label>
<div class="col-sm-10">
<label class="checkbox">
<input type="checkbox" ng-model="$ctrl.durable">
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="filter-markup">Filter</label>
<div class="col-sm-10">
<input id="filter-markup" class="form-control" type="text" maxlength="300"
name="filter" ng-model="$ctrl.filter" placeholder="Filter"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="maxConsumers-markup">Max consumers</label>
<div class="col-sm-10">
<input id="maxConsumers-markup" class="form-control" type="integer" maxlength="300"
name="filter" ng-model="$ctrl.maxConsumers" placeholder="Max consumers"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Purge when no consumers</label>
<div class="col-sm-10">
<label class="checkbox">
<input type="checkbox" ng-model="$ctrl.purgeWhenNoConsumers">
</label>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary"
ng-click="$ctrl.createQueue($ctrl.queueName, $ctrl.routingType, $ctrl.durable, $ctrl.filter, $ctrl.maxConsumers, $ctrl.purgeWhenNoConsumers)"
ng-disabled="!$ctrl.queueName">Create Queue
</button>
</div>
</div>
<div hawtio-confirm-dialog="$ctrl.createDialog"
ok-button-text="Create"
cancel-button-text="Cancel"
on-ok="$ctrl.createQueue($ctrl.queueName, $ctrl.routingType, $ctrl.durable, $ctrl.filter, $ctrl.maxConsumers, $ctrl.purgeWhenNoConsumers)">
<div class="dialog-body">
<p>Queue name <b>{{$ctrl.queueName}}</b> contains unrecommended characters: <code>:</code></p>
<p>This may cause unexpected problems. Are you really sure to create this {{$ctrl.uncapitalisedDestinationType()}}?</p>
</div>
</div>
</form>
<script type="text/ng-template" id="create-queue-instructions.html">
<div>
<p>
This page allows you to create a queue bound to the chosen address.
</p>
<p>
if you want the queue to support JMS like queues, i.e. point to point, then choose anycast. If you
want your address to support JMS like topic subscriptions, publish/subscribe, then choose multicast.
</p>
<p>
Selecting durable means that the queue will survive a restart of the broker.
</p>
<p>
Adding a filter expression will mean that only messages that match that filter will be routed to this queue:
see <a href="https://activemq.apache.org/components/artemis/documentation/latest/filter-expressions.html" target="_blank">Filter Expressions</a>
</p>
<p>
Max consumers will limit how many consumers can consume from a queue at any one time, -1 means no limit.
</p>
<p>
Purge on no consumers means the queue will not start receiving messages until a consumer is attached.
When the last consumer is detached from the queue. The queue is purged (its messages are removed)
and will not receive any more messages until a new consumer is attached.
</p>
</div>
</script>
`,
controller: CreateQueueController
})
.name;
Artemis.log.debug("loaded queue " + Artemis.createQueueModule);
function CreateQueueController($scope, workspace, jolokia, localStorage) {
Artemis.log.debug("loaded queue controller");
var ctrl = this;
Core.initPreferenceScope($scope, localStorage, {
'durable': {
'value': true,
'converter': Core.parseBooleanValue
},
'maxConsumers': {
'value': -1,
'converter': parseInt,
'formatter': parseInt
},
'purgeWhenNoConsumers': {
'value': false,
'converter': Core.parseBooleanValue
}
});
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
ctrl.workspace = workspace;
ctrl.maxConsumers = -1;
ctrl.routingType = "Anycast";
ctrl.filter = "";
ctrl.purgeWhenNoConsumers = false;
ctrl.durable = true;
ctrl.queueName = '';
$scope.$watch('workspace.selection', function () {
workspace.moveIfViewInvalid();
});
function operationSuccess() {
ctrl.queueName = "";
ctrl.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
ctrl.workspace.loadTree();
}
function onError(response) {
Core.notification("error", "Could not create queue: " + response.error);
}
this.createQueue = function (queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers) {
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
if (mbean) {
var selection = workspace.selection;
var entries = selection.entries;
var address = entries["address"];
if (address.charAt(0) === '"' && address.charAt(address.length -1) === '"')
{
address = address.substr(1,address.length -2);
}
$scope.message = "Created queue " + queueName + " durable=" + durable + " filter=" + filter + " routing type=" + routingType + " max consumers=" + maxConsumers + " purge..=" + purgeWhenNoConsumers + " on address " + address;
if (routingType == "Multicast") {
Artemis.log.debug($scope.message);
jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, "MULTICAST", queueName, filter, durable, maxConsumers, purgeWhenNoConsumers, true, Core.onSuccess(operationSuccess, { error: onError }));
} else {
Artemis.log.debug($scope.message);
jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, "ANYCAST", queueName, filter, durable, maxConsumers, purgeWhenNoConsumers, true, Core.onSuccess(operationSuccess, { error: onError }));
}
}
};
}
CreateQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,126 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisDeleteAddress', {
template:
`
<h1>Delete Address
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'delete-address-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<p>
<div class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
This operation cannot be undone. Please be careful!
</div>
</p>
<h2>Delete address</h2>
<p>Remove the address completely.</p>
<button type="submit" class="btn btn-danger" ng-click="$ctrl.deleteDialog = true">
Delete address
</button>
<div hawtio-confirm-dialog="$ctrl.deleteDialog"
title="Confirm delete address"
ok-button-text="Delete"
cancel-button-text="Cancel"
on-ok="$ctrl.deleteAddress()">
<div class="dialog-body">
<p>You are about to delete address <b>{{ $ctrl.selectedName() }}</b>.</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
<script type="text/ng-template" id="delete-address-instructions.html">
<div>
<p>
This page allows you to delete the chosen address on the broker.
</p>
<p>
Note that this will only succeed if the address has no queues bound to it.
</p>
</div>
</script>
`,
controller: DeleteAddressController
})
.name;
Artemis.log.debug("loaded address " + Artemis.addressModule);
function DeleteAddressController($scope, workspace, jolokia, localStorage) {
var ctrl = this;
ctrl.workspace = workspace;
ctrl.deleteDialog = false;
$onInit = function () {
Artemis.log.debug("loaded address controller");
}
$scope.$watch('workspace.selection', function () {
workspace.moveIfViewInvalid();
});
function operationSuccess() {
// lets set the selection to the parent
workspace.removeAndSelectParentNode();
ctrl.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
ctrl.workspace.loadTree();
}
function onError(response) {
Core.notification("error", "Could not delete address: " + response.error);
}
ctrl.deleteAddress = function () {
var selection = workspace.selection;
var entries = selection.entries;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
Artemis.log.debug(mbean);
if (mbean) {
if (selection && jolokia && entries) {
var domain = selection.domain;
var name = entries["address"];
Artemis.log.debug("name = " + name)
name = Core.unescapeHTML(name);
if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
{
name = name.substr(1,name.length -2);
}
name = Artemis.ownUnescape(name);
Artemis.log.debug(name);
var operation;
$scope.message = "Deleted address " + name;
jolokia.execute(mbean, "deleteAddress(java.lang.String)", name, Core.onSuccess(operationSuccess, { error: onError }));
}
}
};
ctrl.selectedName = function () {
var selection = ctrl.workspace.selection;
return selection ? _.unescape(selection.text) : null;
};
}
DeleteAddressController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,172 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisDeleteQueue', {
template:
`<p>
<div class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
These operations cannot be undone. Please be careful!
</div>
</p>
<h2>Delete queue
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'delete-queue-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h2>
<p>Remove the queue completely.</p>
<button type="submit" class="btn btn-danger" ng-click="$ctrl.deleteDialog = true">
Delete Queue
</button>
<div hawtio-confirm-dialog="$ctrl.deleteDialog"
title="Confirm delete address"
ok-button-text="Delete"
cancel-button-text="Cancel"
on-ok="$ctrl.deleteQueue()">
<div class="dialog-body">
<p>You are about to delete queue <b>{{$ctrl.selectedName()}}</b>.</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
<h2>Purge queue
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'purge-queue-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h2>
<p>Remove all messages from queue.</p>
<button type="submit" class="btn btn-danger" ng-click="$ctrl.purgeDialog = true">
Purge Queue
</button>
<div hawtio-confirm-dialog="$ctrl.purgeDialog"
title="Confirm purge address"
ok-button-text="Purge"
cancel-button-text="Cancel"
on-ok="$ctrl.purgeQueue()">
<div class="dialog-body">
<p>You are about to purge queue <b>{{$ctrl.selectedName()}}</b>.</p>
<p>This operation cannot be undone so please be careful.</p>
</div>
</div>
<script type="text/ng-template" id="delete-queue-instructions.html">
<div>
<p>
This will delete the queue and all of the messages it holds
</p>
</div>
</script>
<script type="text/ng-template" id="purge-queue-instructions.html">
<div>
<p>
This will delete all of the messages held within the queue but will not delete the queue
</p>
</div>
</script>
`,
controller: DeleteQueueController
})
.name;
Artemis.log.info("loaded delete queue " + Artemis.createQueueModule);
function DeleteQueueController($scope, workspace, jolokia, localStorage) {
Artemis.log.info("loaded queue controller");
var ctrl = this;
ctrl.workspace = workspace;
ctrl.deleteDialog = false;
ctrl.purgeDialog = false;
$scope.$watch('workspace.selection', function () {
ctrl.workspace.moveIfViewInvalid();
});
function operationSuccess() {
// lets set the selection to the parent
ctrl.workspace.removeAndSelectParentNode();
ctrl.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
ctrl.workspace.loadTree();
}
function onError(response) {
Core.notification("error", "Could not delete address: " + response.error);
}
function operationPurgeSuccess() {
// lets set the selection to the parent
/*$scope.workspace.operationCounter += 1;
Core.$apply($scope);*/
Core.notification("success", $scope.message);
}
function onPurgeError(response) {
Core.notification("error", "Could not purge address: " + response.error);
}
this.deleteQueue = function () {
var selection = ctrl.workspace.selection;
var entries = selection.entries;
var mbean = Artemis.getBrokerMBean(ctrl.workspace, jolokia);
Artemis.log.info(mbean);
if (mbean) {
if (selection && jolokia && entries) {
var domain = selection.domain;
var name = entries["queue"];
Artemis.log.info("name = " + name)
name = Core.unescapeHTML(name);
if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"')
{
name = name.substr(1,name.length -2);
}
name = Artemis.ownUnescape(name);
Artemis.log.info(name);
var operation;
$scope.message = "Deleted queue " + name;
jolokia.execute(mbean, "destroyQueue(java.lang.String)", name, Core.onSuccess(operationPurgeSuccess, { error: onError }));
}
}
};
this.purgeQueue = function () {
var selection = ctrl.workspace.selection;
var entries = selection.entries;
var mbean = selection.objectName;
if (selection && jolokia && entries) {
var name = entries["Destination"] || entries["destinationName"] || selection.title;
name = Core.unescapeHTML(name);
$scope.message = "Purged queue " + name;
jolokia.execute(mbean, "removeAllMessages()", Core.onSuccess(operationSuccess, { error: onPurgeError }));
}
};
ctrl.selectedName = function () {
var selection = ctrl.workspace.selection;
return selection ? _.unescape(selection.text) : null;
};
}
DeleteQueueController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,434 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisBrokerDiagram', {
template:
`<div class="container-topology">
<h1>Broker Diagram
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'diagram-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<pf-topology items="$ctrl.data.items" relations="$ctrl.data.relations" kinds="$ctrl.kinds" icons="$ctrl.data.icons" nodes="$ctrl.nodes" item-selected="$ctrl.itemSelected(item)" search-text="searchText" show-labels="$ctrl.showLabels" tooltip-function="$ctrl.tooltip(node)">
<label>Show labels:
<input type="checkbox" ng-model="$ctrl.showLabels">
</label>
<label>Show addresses:
<input type="checkbox" ng-model="$ctrl.showAddresses">
</label>
<label>Show queues:
<input type="checkbox" ng-model="$ctrl.showQueues">
</label>
<label>Show internal addresses:
<input type="checkbox" ng-model="$ctrl.showInternalAddresses">
</label>
<label>Show internal queues:
<input type="checkbox" ng-model="$ctrl.showInternalQueues">
</label>
<button type="submit" class="btn btn-primary"
ng-click="$ctrl.refresh()">Refresh
</button>
</div>
<div ng-show="$ctrl.showAttributes">
<pf-table-view
config="$ctrl.config"
columns="$ctrl.tableColumns"
items="$ctrl.attributes">
</div>
<script type="text/ng-template" id="diagram-instructions.html">
<div>
<p>
This page is a graphical representation of the cluster topology. It will show all the brokers in the cluster
as well as well as any Adresses and Queues on the broker the console is connected to.
</p>
<p>
It is possible to view the attributes of the addresses, queues and connected broker by left clicking
on each node.
</p>
</div>
</script>
`,
controller: BrokerDiagramController
})
.name;
function BrokerDiagramController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter) {
Artemis.log.debug("loaded browse " + Artemis.browseQueueModule);
var ctrl = this;
ctrl.index = 0;
ctrl.showLabels = false;
ctrl.showAddresses = true;
ctrl.showQueues = true;
ctrl.showInternalAddresses = false;
ctrl.showInternalQueues = false;
$scope.$watch('$ctrl.showAddresses', function () {
if(ctrl.kinds.Address && !ctrl.showAddresses) {
delete ctrl.kinds.Address;
} else if (!ctrl.kinds.Address && ctrl.showAddresses) {
ctrl.kinds.Address = true;
}
});
$scope.$watch('$ctrl.showQueues', function () {
if(ctrl.kinds.Queue && !ctrl.showQueues) {
delete ctrl.kinds.Queue;
} else if (!ctrl.kinds.Queues && ctrl.showQueues) {
ctrl.kinds.Queue = true;
}
});
$scope.$watch('$ctrl.showInternalAddresses', function () {
if(ctrl.kinds.InternalAddress && !ctrl.showInternalAddresses) {
delete ctrl.kinds.InternalAddress;
} else if (!ctrl.kinds.InternalAddress && ctrl.showInternalAddresses) {
ctrl.kinds.InternalAddress = true;
}
});
$scope.$watch('$ctrl.showInternalQueues', function () {
if(ctrl.kinds.InternalQueue && !ctrl.showInternalQueues) {
delete ctrl.kinds.InternalQueue;
} else if (!ctrl.kinds.InternalQueues && ctrl.showInternalQueues) {
ctrl.kinds.InternalQueue = true;
}
});
ctrl.datasets = [];
//icons can be found at https://www.patternfly.org/v3/styles/icons/index.html
ctrl.serverIcon = "\ue90d";
Artemis.log.debug(ctrl.serverIcon);
ctrl.addressIcon = "";//\ue91a";
ctrl.queueIcon = "";//\ue90a";
ctrl.icons = {
"ThisBroker": {
"type": "glyph",
"icon": ctrl.serverIcon,
"background": "#456BD9",
"fontfamily": "PatternFlyIcons-webfont"
},
"MasterBroker": {
"type": "glyph",
"icon": ctrl.serverIcon,
"fontfamily": "PatternFlyIcons-webfont"
},
"SlaveBroker": {
"type": "glyph",
"icon": ctrl.serverIcon,
"fontfamily": "PatternFlyIcons-webfont"
},
"Address": {
"type": "glyph",
"icon": ctrl.addressIcon,
"fontfamily": "PatternFlyIcons-webfont"
},
"InternalAddress": {
"type": "glyph",
"icon": ctrl.addressIcon,
"fontfamily": "PatternFlyIcons-webfont"
},
"Queue": {
"type": "glyph",
"background": "#456BD9",
"icon": ctrl.queueIcon,
"fontfamily": "PatternFlyIcons-webfont"
},
"InternalQueue": {
"type": "glyph",
"background": "#456BD9",
"icon": ctrl.queueIcon,
"fontfamily": "PatternFlyIcons-webfont"
}
};
load();
function load() {
ctrl.items = {};
ctrl.relations = [];
ctrl.datasets.push({
"items": ctrl.items,
"relations": ctrl.relations,
"icons": ctrl.icons
});
Artemis.log.debug("index " + ctrl.index);
ctrl.data = ctrl.datasets[ctrl.index];
ctrl.data.url = "fooBar";
ctrl.kinds = {
"ThisBroker": true,
"MasterBroker": true,
"SlaveBroker": true,
"Address": true,
"Queue": true
};
ctrl.icons = ctrl.data.icons;
ctrl.nodes = {
"ThisBroker": {
"name": "ThisBroker",
"title": "hello",
"enabled": true,
"radius": 28,
"textX": 0,
"textY": 5,
"height": 30,
"width": 30,
"icon": ctrl.icons["ThisBroker"].icon,
"fontFamily": ctrl.icons["ThisBroker"].fontfamily
},
"MasterBroker": {
"name": "MasterBroker",
"enabled": true,
"radius": 28,
"textX": 0,
"textY": 5,
"height": 30,
"width": 30,
"icon": ctrl.icons["MasterBroker"].icon,
"fontFamily": ctrl.icons["MasterBroker"].fontfamily
},
"SlaveBroker": {
"name": "SlaveBroker",
"enabled": true,
"radius": 28,
"textX": 0,
"textY": 5,
"height": 30,
"icon": ctrl.icons["SlaveBroker"].icon,
"fontFamily": ctrl.icons["SlaveBroker"].fontfamily
},
"Address": {
"name": "Address",
"enabled": ctrl.showDestinations,
"radius": 16,
"textX": 0,
"textY": 5,
"height": 18,
"width": 18,
"icon": ctrl.icons["Address"].icon,
"fontFamily": ctrl.icons["Address"].fontfamily
},
"Queue": {
"name": "Queue",
"enabled": ctrl.showDestinations,
"radius": 16,
"textX": 0,
"textY": 5,
"height": 18,
"width": 18,
"icon": ctrl.icons["Queue"].icon,
"fontFamily": ctrl.icons["Queue"].fontfamily
}
};
ctrl.tableColumns = [
{ header: 'attribute', itemField: 'attribute' },
{ header: 'value', itemField: 'value' }
];
ctrl.attributes = [];
ctrl.config = {
selectionMatchProp: 'attribute',
showCheckboxes: false
};
ctrl.showAttributes = false;
loadThisBroker();
Core.$apply($scope);
}
ctrl.itemSelected = function(item) {
ctrl.showAttributes = false;
ctrl.attributes = [];
if (!item || !item.mbean) {
Core.$apply($scope);
return;
}
var atts = jolokia.request({ type: "read", mbean: item.mbean}, {method: "post"});
var val = atts.value;
if (val) {
angular.forEach(val, function (value, key) {
attribute = {
"attribute": key,
"value": value
}
ctrl.attributes.push(attribute);
});
}
ctrl.showAttributes = true;
Core.$apply($scope);
}
ctrl.tooltip = function (node) {
var status = [
'Name: ' + node.item.name,
'Type: ' + node.item.brokerKind
];
return status;
}
ctrl.refresh = function () {
ctrl.datasets = [];
load();
}
function loadThisBroker() {
var mBean = Artemis.getBrokerMBean(workspace, jolokia);
var atts = jolokia.request({ type: "read", mbean: mBean}, {method: "post"});
var val = atts.value;
var details = Core.parseMBean(mBean);
if (details) {
var properties = details['attributes'];
Artemis.log.debug("Got broker: " + mBean + " properties: " + angular.toJson(properties, true));
if (properties) {
var brokerAddress = properties["broker"] || "unknown";
var brokerName = artemisJmxDomain + ":broker=" + brokerAddress;
var backupRes = jolokia.request({ type: "read", mbean: mBean, attribute: "Backup"}, {method: "get"});
var isBackup = backupRes.value;
var nodeId = val["NodeID"];
var response = jolokia.request({ type: 'exec', mbean: mBean, operation: 'listNetworkTopology()' }, Core.onSuccess(null));
var responseValue = response.value;
var remoteBrokers = angular.fromJson(responseValue);
var thisBroker = remoteBrokers.find(broker => broker.nodeID == nodeId);
if(!thisBroker) {
if(isBackup) {
thisBroker = {
backup: "broker"
};
} else {
thisBroker = {
live: "broker"
};
}
}
if (thisBroker.live) {
ctrl.items[thisBroker.live] = {
"name": thisBroker.live,
"kind": "ThisBroker",
"brokerKind": "master",
"status": "broker",
"display_kind": "Server",
"mbean": mBean
}
}
if (thisBroker.backup) {
ctrl.items[thisBroker.backup] = {
"name": thisBroker.backup,
"kind": "SlaveBroker",
"brokerKind": "slave",
"status": "broker",
"display_kind": "Server"
};
if (thisBroker.live) {
ctrl.relations.push({
"source": thisBroker.live,
"target": thisBroker.backup
});
}
}
createAddresses(mBean, thisBroker.live)
}
angular.forEach(remoteBrokers, function (remoteBroker) {
if (nodeId != remoteBroker.nodeID) {
if (remoteBroker.live) {
ctrl.items[remoteBroker.live] = {
"name": remoteBroker.live,
"kind": "MasterBroker",
"brokerKind": "master",
"status": "broker",
"display_kind": "Server"
};
//if we arent a backup then connect to it as we are in the cluster
if(!isBackup) {}
ctrl.relations.push({
"source": thisBroker.live,
"target": remoteBroker.live
});
}
if (remoteBroker.backup) {
ctrl.items[remoteBroker.backup] = {
"name": remoteBroker.backup,
"kind": "SlaveBroker",
"brokerKind": "slave",
"status": "broker",
"display_kind": "Server"
};
ctrl.relations.push({
"source": remoteBroker.backup,
"target": remoteBroker.live
});
}
}
});
}
}
function createAddresses(brokerMBean, brokerId) {
jolokia.search(brokerMBean + ",component=addresses,*", Core.onSuccess(function (response) {
angular.forEach(response, function (objectName) {
var details = Core.parseMBean(objectName);
if (details) {
var properties = details['attributes'];
if (properties) {
if (!properties.subcomponent) {
Artemis.log.debug("Got Address: " + objectName + " properties: " + angular.toJson(properties, true));
addressKind = properties.address.startsWith("$", 1) || properties.address.startsWith("notif", 1) ? "InternalAddress" : "Address";
ctrl.items[properties.address] = {
"name": properties.address,
"kind": addressKind,
"brokerKind": "address",
"status": "Valid",
"display_kind": "Server",
"mbean": objectName
}
ctrl.relations.push({
"source": brokerId,
"target": properties.address
});
}
if (properties.queue) {
Artemis.log.debug("Got Queue: " + objectName + " properties: " + angular.toJson(properties, true));
queueKind = properties.queue.startsWith("$", 1) || properties.queue.startsWith("notif", 1) ? "InternalQueue" : "Queue";
ctrl.items["queue." + properties.queue] = {
"name": properties.queue,
"kind": queueKind,
"brokerKind": "queue",
"status": "Valid",
"display_kind": "Service",
"mbean": objectName
}
ctrl.relations.push({
"source": properties.address,
"target": "queue." + properties.queue
});
}
}
}
});
}));
}
}
BrokerDiagramController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,51 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis._module
.run(configureHelp)
.name;
function configureHelp(helpRegistry, $templateCache) {
var path = 'plugin/help.md';
helpRegistry.addUserDoc('artemis', path);
//this is indented to render correctly as it is markdown
$templateCache.put(path, `
### Artemis
Click [Artemis](#/jmx/attributes?tab=artemis) in the top navigation bar to see the Artemis specific plugin. (The Artemis tab won't appear if there is no broker in this JVM). The Artemis plugin works very much the same as the JMX plugin however with a focus on interacting with an Artemis broker.
The tree view on the left-hand side shows the top level JMX tree of each broker instance running in the JVM. Expanding the tree will show the various MBeans registered by Artemis that you can inspect via the **Attributes** tab.
#### Creating a new Address
To create a new address simply click on the broker or the address folder in the jmx tree and click on the create tab.
Once you have created an address you should be able to **Send** to it by clicking on it in the jmx tree and clicking on the send tab.
#### Creating a new Queue
To create a new queue click on the address you want to bind the queue to and click on the create tab.
Once you have created a queue you should be able to **Send** a message to it or **Browse** it or view the **Attributes** or **Charts**. Simply click on the queue in th ejmx tree and click on the appropriate tab.
You can also see a graphical view of all brokers, addresses, queues and their consumers using the **Diagram** tab.
`);
}
configureHelp.$inject = ['helpRegistry', '$templateCache'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,238 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis.log.info("loading navigation");
var TAB_CONFIG = {
attributes: {
title: 'Attributes',
route: '/artemis/attributes'
},
operations: {
title: 'Operations',
route: '/artemis/operations'
},
chart: {
title: 'Chart',
route: '/artemis/charts'
},
createAddress: {
title: 'Create address',
route: '/artemis/artemisCreateAddress'
},
deleteAddress: {
title: 'Delete address',
route: '/artemis/artemisDeleteAddress'
},
createQueue: {
title: 'Create queue',
route: '/artemis/artemisCreateQueue'
},
deleteQueue: {
title: 'Delete queue',
route: '/artemis/artemisDeleteQueue'
},
sendMessage: {
title: 'Send message',
route: '/artemis/artemisSendMessage'
},
browseQueue: {
title: 'Browse queue',
route: '/artemis/artemisBrowseQueue'
},
brokerDiagram: {
title: 'Broker diagram',
route: '/artemis/artemisBrokerDiagram'
},
artemisStatus: {
title: 'Status',
route: '/artemis/artemisStatus'
},
artemisConnections: {
title: 'Connections',
route: '/artemis/artemisConnections'
},
artemisSessions: {
title: 'Sessions',
route: '/artemis/artemisSessions'
},
artemisConsumers: {
title: 'Consumers',
route: '/artemis/artemisConsumers'
},
artemisProducers: {
title: 'Producers',
route: '/artemis/artemisProducers'
},
artemisAddresses: {
title: 'Addresses',
route: '/artemis/artemisAddresses'
},
artemisQueues: {
title: 'Queues',
route: '/artemis/artemisQueues'
}
};
Artemis._module
.config(configureRoutes)
.component('artemisNavigation', {
template: `<hawtio-tabs tabs="$ctrl.tabs" on-change="$ctrl.goto(tab)"></hawtio-tabs>`,
controller: ArtemisNavigationController
})
.name;
Artemis.log.info("loaded navigation " + Artemis.navigationModule);
function ArtemisNavigationController($scope, $location, workspace, localStorage, jolokia) {
'ngInject';
var ctrl = this;
this.$location = $location;
artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
$scope.$on('jmxTreeClicked', function () {
ctrl.tabs = getTabs();
var tab = _.find(ctrl.tabs, { path: ctrl.$location.path() });
if (!tab) {
tab = ctrl.tabs[0];
}
ctrl.$location.path(tab.path);
});
ArtemisNavigationController.prototype.$onInit = function () {
this.tabs = getTabs();
};
ArtemisNavigationController.prototype.goto = function (tab) {
this.$location.path(tab.path);
};
ctrl.showCreateAddress = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'createAddress');
ctrl.showDeleteAddress = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'deleteAddress');
ctrl.showCreateQueue = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'createQueue');
ctrl.showDeleteQueue = hasInvokeRights(jolokia, Artemis.getBrokerMBean(workspace, jolokia), 'destroyQueue');
function getTabs() {
var tabs = [];
var enabledRoutes = Object.keys(TAB_CONFIG)
.map(function (config) { return TAB_CONFIG[config].route; })
.filter(function (route) { return _.startsWith(route, '/artemis'); });
if (enabledRoutes.length > 0) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisStatus.title, TAB_CONFIG.artemisStatus.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisConnections.title, TAB_CONFIG.artemisConnections.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisSessions.title, TAB_CONFIG.artemisSessions.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisConsumers.title, TAB_CONFIG.artemisConsumers.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisProducers.title, TAB_CONFIG.artemisProducers.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisAddresses.title, TAB_CONFIG.artemisAddresses.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.artemisQueues.title, TAB_CONFIG.artemisQueues.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.attributes.title, TAB_CONFIG.attributes.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.operations.title, TAB_CONFIG.operations.route));
tabs.push(new Nav.HawtioTab(TAB_CONFIG.chart.title, TAB_CONFIG.chart.route));
if (shouldShowCreateAddressTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.createAddress.title, TAB_CONFIG.createAddress.route));
}
if (shouldShowDeleteAddressTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.deleteAddress.title, TAB_CONFIG.deleteAddress.route));
}
if (shouldShowCreateQueueTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.createQueue.title, TAB_CONFIG.createQueue.route));
}
if (shouldShowDeleteQueueTab()) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.deleteQueue.title, TAB_CONFIG.deleteQueue.route));
}
if (shouldShowSendMessageTab(workspace)) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.sendMessage.title, TAB_CONFIG.sendMessage.route));
}
if (shouldShowBrowseMessageTab(workspace)) {
tabs.push(new Nav.HawtioTab(TAB_CONFIG.browseQueue.title, TAB_CONFIG.browseQueue.route));
}
tabs.push(new Nav.HawtioTab(TAB_CONFIG.brokerDiagram.title, TAB_CONFIG.brokerDiagram.route));
}
return tabs;
}
function shouldShowCreateAddressTab() {
return workspace.selectionHasDomainAndLastFolderName(artemisJmxDomain, 'addresses') && ctrl.showCreateAddress;
}
function shouldShowDeleteAddressTab() {
return workspace.hasDomainAndProperties(artemisJmxDomain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'diverts'}) && ctrl.showDeleteAddress;
}
function shouldShowCreateQueueTab() {
return workspace.hasDomainAndProperties(artemisJmxDomain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && !workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'diverts'}) && ctrl.showCreateQueue;
}
function shouldShowDeleteQueueTab() {
return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && ctrl.showDeleteQueue;
}
function shouldShowSendMessageTab(workspace) {
return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && hasQueueinvokeRights(workspace, "sendMessage");
}
function shouldShowBrowseMessageTab(workspace) {
return workspace.hasDomainAndProperties(artemisJmxDomain, {'subcomponent': 'queues'}) && hasQueueinvokeRights(workspace, "browse") && hasQueueinvokeRights(workspace, "countMessages");
}
function hasInvokeRights(jolokia, mbean, operation) {
var response = jolokia.request({
type: 'exec',
mbean: 'hawtio:type=security,area=jmx,name=ArtemisJMXSecurity',
operation: 'canInvoke(java.lang.String, java.lang.String)',
arguments: [mbean, operation] },
Core.onSuccess(null));
Artemis.log.info(operation + "=" + response.value);
return response.value;
}
function hasQueueinvokeRights(workspace, operation) {
var selection = workspace.selection;
if (!selection)
return false;
var mbean = selection.objectName;
if (!mbean)
return false;
return hasInvokeRights(jolokia, mbean, operation)
}
}
ArtemisNavigationController.$inject = ['$scope', '$location', 'workspace', 'localStorage', 'jolokia']
function configureRoutes($routeProvider) {
$routeProvider.
when('/artemis/attributes', { templateUrl: 'plugins/jmx/html/attributes/attributes.html' }).
when('/artemis/operations', { template: '<operations></operations>' }).
when('/artemis/charts', { templateUrl: 'plugins/jmx/html/charts.html' }).
when('/artemis/charts/edit', { templateUrl: 'plugins/jmx/html/chartEdit.html' }).
when('/artemis/artemisCreateAddress', { template: '<artemis-create-address></artemis-create-address>'}).
when('/artemis/artemisDeleteAddress', { template: '<artemis-delete-address></artemis-delete-address>'}).
when('/artemis/artemisCreateQueue', { template: '<artemis-create-queue></artemis-create-queue>'}).
when('/artemis/artemisDeleteQueue', { template: '<artemis-delete-queue></artemis-delete-queue>'}).
when('/artemis/artemisSendMessage', { template: '<artemis-send-message></artemis-send-message>'}).
when('/artemis/artemisBrowseQueue', { template: '<artemis-browse-queue></artemis-browse-queue>'}).
when('/artemis/artemisBrokerDiagram', { template: '<artemis-broker-diagram></artemis-broker-diagram>'}).
when('/artemis/artemisStatus', { template: '<artemis-status></artemis-status>'}).
when('/artemis/artemisConnections', { template: '<artemis-connections></artemis-connections>'}).
when('/artemis/artemisSessions', { template: '<artemis-sessions></artemis-sessions>'}).
when('/artemis/artemisConsumers', { template: '<artemis-consumers></artemis-consumers>'}).
when('/artemis/artemisProducers', { template: '<artemis-producers></artemis-producers>'}).
when('/artemis/artemisAddresses', { template: '<artemis-addresses></artemis-addresses>'}).
when('/artemis/artemisQueues', { template: '<artemis-queues></artemis-queues>'});
}
configureRoutes.$inject = ['$routeProvider'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,113 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis._module
.controller("Artemis.PreferencesController", ["$scope", "localStorage", "userDetails", "$rootScope", function ($scope, localStorage, userDetails, $rootScope) {
Core.initPreferenceScope($scope, localStorage, {
'artemisUserName': {
'value': userDetails.username ? userDetails.username : ""
},
'artemisPassword': {
'value': userDetails.password ? userDetails.password : ""
},
'artemisDLQ': {
'value': "DLQ"
},
'artemisExpiryQueue': {
'value': "ExpiryQueue"
},
'ArtemisBrowseBytesMessages': {
'value': 99,
'post': function (newValue) {
$scope.$emit('ArtemisBrowseBytesMessages', newValue);
}
}
})}])
.run(configurePreferences)
.name;
function configurePreferences(preferencesRegistry, $templateCache, workspace) {
Artemis.log.info("£££££££££££££££££££££££££rwerewrwerwerwe£££££££££££££££");
var path = 'plugin/preferences.html';
preferencesRegistry.addTab("Artemis", path, function () {
return workspace.treeContainsDomainAndProperties("org.apache.activemq.artemis");
});
$templateCache.put(path,
`<form class="form-horizontal artemis-preferences-form" ng-controller="Artemis.PreferencesController">
<div class="form-group">
<label class="col-md-2 control-label" for="artemisUserName">
Artemis user name
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
</label>
<div class="col-md-6">
<input id="artemisUserName" type="text" class="form-control" ng-model="artemisUserName"/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisPassword">
Artemis password
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The user name to be used when connecting to the broker"></span>
</label>
<div class="col-md-6">
<input id="artemisPassword" type="password" class="form-control" ng-model="artemisPassword"/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisDLQ">
The DLQ of the Broker
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Dead Letter Queue of the Broker"></span>
</label>
<div class="col-md-6">
<input type="text" id="artemisDLQ" ng-model="artemisDLQ">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="artemisExpiryQueue">
The Expiry of the Broker
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="The Expiry Queue of the Broker"></span>
</label>
<div class="col-md-6">
<input type="text" id="artemisExpiryQueue" ng-model="artemisExpiryQueue">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="Browse Byte Messages">
Browse Bytes Messages
<span class="pficon pficon-info" data-toggle="tooltip" data-placement="top" title="Browsing byte messages should display the message body as this"></span>
</label>
<div class="col-md-6">
<select id="ArtemisBrowseBytesMessages" class="form-control" ng-model="ArtemisBrowseBytesMessages">
<option value="99">Off</option>
<option value="8">Decimal</option>
<option value="4">Hex</option>
<option value="2">Decimal and Text</option>
<option value="1">Hex and Text</option>
</select>
</div>
</div>
</form>`
);
}
configurePreferences.$inject = ['preferencesRegistry', '$templateCache', 'workspace'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,194 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis.log.info("loading producers");
Artemis._module.component('artemisProducers', {
template:
`<h1>Browse Consumers
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'producers-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
items="$ctrl.producers">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<script type="text/ng-template" id="producers-instructions.html">
<div>
<p>
This page allows you to browse all producers currently open on the broker. These can be narrowed down
by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
click on the <span class="fa fa-search"></span> button.
</p>
<p>
You can navigate to the producers session by clicking on the <code>Session</code> field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: ProducersController
})
.name;
function ProducersController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisProducer, artemisAddress, artemisSession) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allProducers = [];
ctrl.producers = [];
ctrl.pageNumber = 1;
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'SESSION_ID', name: 'Session ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USER', name: 'User'},
{id: 'ADDRESS', name: 'Address'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "id"
},
text: {
fieldText: "Filter Field..",
operationText: "Operation..",
sortOrderText: "ascending",
sortByText: "ID"
}
};
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'id' },
{ header: 'Session', itemField: 'session' , templateFn: function(value, item) { return '<a href="#" onclick="selectSession(\'' + item.session + '\')">' + value + '</a>' }},
{ header: 'Client ID', itemField: 'clientID' },
{ header: 'Protocol', itemField: 'protocol' },
{ header: 'User', itemField: 'user' },
{ header: 'Address', itemField: 'address', templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
{ header: 'Remote Address', itemField: 'remoteAddress' },
{ header: 'Local Address', itemField: 'localAddress' }
];
ctrl.refresh = function () {
ctrl.refreshed = true;
ctrl.pagination.load();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "id";
ctrl.filter.text.fieldText = "Filter Field..";
ctrl.filter.text.operationText = "Operation..";
ctrl.filter.text.sortOrderText = "ascending";
ctrl.filter.text.sortByText = "ID";
ctrl.refreshed = true;
artemisProducer.producer = null;
ctrl.pagination.load();
};
selectAddress = function (address) {
Artemis.log.info("navigating to address:" + address)
artemisAddress.address = { address: address };
$location.path("artemis/artemisAddresses");
};
selectSession = function (session) {
Artemis.log.info("navigating to session:" + session)
artemisSession.session = { session: session };
$location.path("artemis/artemisSessions");
};
if (artemisProducer.producer) {
Artemis.log.info("navigating to producer = " + artemisProducer.producer.sessionID);
ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisProducer.producer.sessionID;
}
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listProducers(java.lang.String, int, int)';
var producerFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(producerFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
ctrl.pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list sessions" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.producers = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.producers.push(value);
});
ctrl.pagination.page(data["count"]);
allProducers = ctrl.producers;
ctrl.producers = allProducers;
Core.$apply($scope);
}
ctrl.pagination.load();
}
ProducersController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisProducer', 'artemisAddress', 'artemisSession'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,255 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
//Artemis.log.info("loading addresses");
Artemis._module.component('artemisQueues', {
template:
`<h1>Browse Queues
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'queues-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
items="$ctrl.queues">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<script type="text/ng-template" id="queues-instructions.html">
<div>
<p>
This page allows you to browse all queues on the broker. These can be narrowed down
by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
click on the <span class="fa fa-search"></span> button.
</p>
<p>
You can also navigate directly to the JMX attributes and operations tabs by using the <code>attributes</code>
and <code>operations</code> button under the <code>Actions</code> column.You can navigate to the
queues address by clicking on the <code>Address</code> field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: QueuesController
})
.name;
function QueuesController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisQueue, artemisAddress) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allAddresses = [];
ctrl.queues = [];
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'NAME', name: 'Name'},
{id: 'CONSUMER_ID', name: 'Consumer ID'},
{id: 'ADDRESS', name: 'Address'},
{id: 'FILTER', name: 'Filter'},
{id: 'MAX_CONSUMERS', name: 'maxConsumers'},
{id: 'ROUTING_TYPE', name: 'Routing Type'},
{id: 'PURGE_ON_NO_CONSUMERS', name: 'Purge On No Consumers'},
{id: 'USER', name: 'User'},
{id: 'MESSAGE_COUNT', name: 'Message Count'},
{id: 'DELIVERING_COUNT', name: 'Delivering Count'},
{id: 'PAUSED', name: 'Paused'},
{id: 'TEMPORARY', name: 'Temporary'},
{id: 'AUTO_CREATED', name: 'Auto Created'},
{id: 'RATE', name: 'Rate'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "id"
},
text: {
fieldText: "Filter Field..",
operationText: "Operation..",
sortOrderText: "ascending",
sortByText: "ID"
}
};
ctrl.tableActionButtons = [
{
name: 'attributes',
title: 'Navigate to attributes',
actionFn: navigateToQueuesAtts
},
{
name: 'operations',
title: 'navigate to operations',
actionFn: navigateToQueuesOps
}
];
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'id' },
{ header: 'Name', itemField: 'name' },
{ header: 'Routing Types', itemField: 'routingTypes' },
{ header: 'Queue Count', itemField: 'queueCount' },
{ header: 'Address', itemField: 'address' , templateFn: function(value, item) { return '<a href="#" onclick="selectAddress(\'' + item.address + '\')">' + value + '</a>' }},
{ header: 'Routing Type', itemField: 'routingType' },
{ header: 'Filter', itemField: 'filter' },
{ header: 'Durable', itemField: 'durable' },
{ header: 'Max Consumers', itemField: 'maxConsumers' },
{ header: 'Purge On No Consumers', itemField: 'purgeOnNoConsumers' },
{ header: 'Consumer Count', itemField: 'consumerCount' },
{ header: 'Rate', itemField: 'rate' },
{ header: 'Message Count', itemField: 'messageCount' },
{ header: 'Paused', itemField: 'paused' },
{ header: 'Temporary', itemField: 'temporary' },
{ header: 'Auto Created', itemField: 'autoCreated' },
{ header: 'User', itemField: 'user' },
{ header: 'Total Messages Added', itemField: 'messagesAdded' },
{ header: 'Total Messages Acked', itemField: 'messagesAcked' },
{ header: 'Delivering Count', itemField: 'deliveringCount' },
{ header: 'Messages Killed', itemField: 'messagesKilled' },
{ header: 'Direct Deliver', itemField: 'directDeliver' }
];
ctrl.refresh = function () {
ctrl.refreshed = true;
loadTable();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "id";
ctrl.filter.text.fieldText = "Filter Field..";
ctrl.filter.text.operationText = "Operation..";
ctrl.filter.text.sortOrderText = "ascending";
ctrl.filter.text.sortByText = "ID";
ctrl.refreshed = true;
ctrl.pagination.load();
};
if (artemisQueue.queue) {
Artemis.log.info("navigating to queue = " + artemisQueue.queue.queue);
ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisQueue.queue.queue;
}
if (artemisAddress.address) {
Artemis.log.info("navigating to queue = " + artemisAddress.address.address);
ctrl.filter.values.field = ctrl.filter.fieldOptions[3].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisAddress.address.address;
}
function navigateToQueuesAtts(action, item) {
$location.path("artemis/attributes").search({"tab": "artemis", "nid": getQueuesNid(item, $location)});
};
function navigateToQueuesOps(action, item) {
$location.path("artemis/operations").search({"tab": "artemis", "nid": getQueuesNid(item, $location)});
};
selectAddress = function (address) {
Artemis.log.info("navigating to address:" + address)
artemisAddress.address = { address: address };
$location.path("artemis/artemisAddresses");
};
function getQueuesNid(item, $location) {
var rootNID = getRootNid($location);
var targetNID = rootNID + "addresses-" + item.address + "-queues-" + item.routingType.toLowerCase() + "-" + item.name;
Artemis.log.info("targetNID=" + targetNID);
return targetNID;
}
function getRootNid($location) {
var currentNid = $location.search()['nid'];
Artemis.log.info("current nid=" + currentNid);
var firstDash = currentNid.indexOf('-');
var secondDash = currentNid.indexOf('-', firstDash + 1);
var thirdDash = currentNid.indexOf('-', secondDash + 1);
if (thirdDash < 0) {
return currentNid + "-";
}
var rootNID = currentNid.substring(0, thirdDash + 1);
return rootNID;
}
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listQueues(java.lang.String, int, int)';
var queuesFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(queuesFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
ctrl.pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list sessions" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.queues = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.queues.push(value);
});
ctrl.pagination.page(data["count"]);
allQueues = ctrl.queues;
ctrl.queues = allQueues;
Core.$apply($scope);
}
ctrl.pagination.load();
}
QueuesController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisQueue', 'artemisAddress'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,246 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis.log.info("loading send message");
Artemis._module.component('artemisSendMessage', {
template:
`<h1>Send Message
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'send-message-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div class="alert alert-warning" ng-show="$ctrl.noCredentials">
<span class="pficon pficon-warning-triangle-o"></span>
<strong>No credentials set for endpoint!</strong>
Please set your username and password in the
<a href="#" class="alert-link" ng-click="$ctrl.openPrefs()">Preferences</a> page.
</div>
<div class="row artemis-message-configuration">
<div class="col-sm-12">
<form>
<div class="form-group">
<label>Durable </label>
<input id="durable" type="checkbox" ng-model="$ctrl.durable" value="true">
</div>
</form>
</div>
</div>
<h3>Headers</h3>
<div class="form-group" ng-if="$ctrl.headers.length > 0">
<table class="scr-component-references-table table">
<tbody>
<tr class="input-group" ng-repeat="header in $ctrl.headers">
<td><input type="text" class="form-control" ng-model="header.name" placeholder="Name" autocomplete="off" id="name"></td>
<td><input type="text" class="form-control" ng-model="header.value" placeholder="Value" autocomplete="off" id="value"></td>
<td><div class="input-group-prepend">
<button type="button" class="btn btn-default" title="Delete" ng-click="$ctrl.removeHeader(header)">
<span class="pficon pficon-delete"></span>
</button>
</div></td>
</tr>
</tbody>
</table>
</div>
<p>
<button type="button" class="btn btn-primary artemis-add-message-button" ng-click="$ctrl.addHeader()">Add Header</button>
</p>
<h3>Body</h3>
<form>
<div class="form-group">
<div hawtio-editor="$ctrl.message" mode="codeMirrorOptions.mode.name"></div>
</div>
<div class="form-group">
<select class="form-control artemis-send-message-format" ng-model="codeMirrorOptions.mode.name">
<option value="javascript">JSON</option>
<option value="xml">XML</option>
</select>
<button class="btn btn-default" ng-click="$ctrl.formatMessage()"
title="Automatically pretty prints the message so its easier to read">Format
</button>
</div>
</form>
<p>
<button type="button" class="btn btn-primary artemis-send-message-button" ng-click="$ctrl.sendMessage($ctrl.durable)">Send message</button>
</p>
<script type="text/ng-template" id="send-message-instructions.html">
<div>
<p>
This page allows you to send a message to the chosen queue. The message will be of type <code>text</code>
message and it will be possible to add headers to the message. The sending of the message will be authenticated
using the username and password set ion <code>preferences</code>, if this is not set then these will
be null.
</p>
</div>
</script>
`,
controller: SendMessageController
})
.name;
Artemis.log.info("loaded queue " + Artemis.createQueueModule);
function SendMessageController($route, $scope, $element, $timeout, workspace, jolokia, localStorage, $location, artemisMessage) {
Core.initPreferenceScope($scope, localStorage, {
'durable': {
'value': true,
'converter': Core.parseBooleanValue
}
});
var ctrl = this;
ctrl.noCredentials = false;
ctrl.durable = true;
ctrl.message = "";
ctrl.headers = [];
// bind model values to search params...
Core.bindModelToSearchParam($scope, $location, "tab", "subtab", "compose");
Core.bindModelToSearchParam($scope, $location, "searchText", "q", "");
// only reload the page if certain search parameters change
Core.reloadWhenParametersChange($route, $scope, $location);
ctrl.checkCredentials = function () {
ctrl.noCredentials = (Core.isBlank(localStorage['artemisUserName']) || Core.isBlank(localStorage['artemisPassword']));
};
if ($location.path().indexOf('artemis') > -1) {
ctrl.localStorage = localStorage;
$scope.$watch('localStorage.artemisUserName', ctrl.checkCredentials);
$scope.$watch('localStorage.artemisPassword', ctrl.checkCredentials);
//prefill if it's a resent
if (artemisMessage.message !== null) {
ctrl.message = artemisMessage.message.bodyText;
if (artemisMessage.message.PropertiesText !== null) {
for (var p in artemisMessage.message.StringProperties) {
ctrl.headers.push({name: p, value: artemisMessage.message.StringProperties[p]});
}
}
}
// always reset at the end
artemisMessage.message = null;
}
this.openPrefs = function () {
Artemis.log.info("opening prefs");
$location.path('/preferences').search({'pref': 'Artemis'});
}
var LANGUAGE_FORMAT_PREFERENCE = "defaultLanguageFormat";
var sourceFormat = workspace.getLocalStorage(LANGUAGE_FORMAT_PREFERENCE) || "javascript";
$scope.codeMirrorOptions = CodeEditor.createEditorSettings({
mode: {
name: sourceFormat
}
});
$scope.$on('hawtioEditor_default_instance', function (event, codeMirror) {
$scope.codeMirror = codeMirror;
});
ctrl.addHeader = function () {
ctrl.headers.push({name: "", value: ""});
// lets set the focus to the last header
if ($element) {
$timeout(function () {
var lastHeader = $element.find("input.headerName").last();
lastHeader.focus();
}, 100);
}
}
this.removeHeader = function (header) {
var index = ctrl.headers.indexOf(header);
ctrl.headers.splice(index, 1);
};
ctrl.defaultHeaderNames = function () {
var answer = [];
function addHeaderSchema(schema) {
angular.forEach(schema.definitions.headers.properties, function (value, name) {
answer.push(name);
});
}
addHeaderSchema(Artemis.jmsHeaderSchema);
return answer;
};
function operationSuccess() {
Core.notification("success", "Message sent!");
ctrl.headers = [];
ctrl.message = "";
};
function onError(response) {
Core.notification("error", "Could not send message: " + response.error);
}
ctrl.formatMessage = function () {
CodeEditor.autoFormatEditor($scope.codeMirror);
};
ctrl.sendMessage = function (durable) {
var body = ctrl.message;
Artemis.log.info(body);
doSendMessage(ctrl.durable, body);
};
function doSendMessage(durable, body) {
var selection = workspace.selection;
if (selection) {
var mbean = selection.objectName;
if (mbean) {
var headers = null;
if (ctrl.headers.length) {
headers = {};
angular.forEach(ctrl.headers, function (object) {
var key = object.name;
if (key) {
headers[key] = object.value;
}
});
Artemis.log.debug("About to send headers: " + JSON.stringify(headers));
}
var user = ctrl.localStorage["artemisUserName"];
var pwd = ctrl.localStorage["artemisPassword"];
if (!headers) {
headers = {};
}
var type = 3;
Artemis.log.debug(headers);
Artemis.log.debug(type);
Artemis.log.debug(body);
Artemis.log.debug(durable);
jolokia.execute(mbean, "sendMessage(java.util.Map, int, java.lang.String, boolean, java.lang.String, java.lang.String)", headers, type, body, durable, user, pwd, Core.onSuccess(operationSuccess, { error: onError }));
}
}
}
}
SendMessageController.$inject = ['$route', '$scope', '$element', '$timeout', 'workspace', 'jolokia', 'localStorage', '$location', 'artemisMessage'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,251 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis.log.info("loading sessions");
Artemis._module.component('artemisSessions', {
template:
`<h1>Browse Sessions
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'sessions-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div ng-include="'plugin/artemistoolbar.html'"></div>
<pf-table-view config="$ctrl.tableConfig"
columns="$ctrl.tableColumns"
action-buttons="$ctrl.tableActionButtons"
items="$ctrl.sessions">
</pf-table-view>
<div ng-include="'plugin/artemispagination.html'"></div>
<div hawtio-confirm-dialog="$ctrl.closeDialog" title="Close Session?"
ok-button-text="Close"
cancel-button-text="Cancel"
on-ok="$ctrl.closeSession()">
<div class="dialog-body">
<p class="alert alert-warning">
<span class="pficon pficon-warning-triangle-o"></span>
You are about to close the selected session: {{$ctrl.sessionToDelete}}
<p>Are you sure you want to continue.</p>
</p>
</div>
</div>
<script type="text/ng-template" id="sessions-instructions.html">
<div>
<p>
This page allows you to browse all session currently open on the broker. These can be narrowed down
by specifying a filter and also sorted using the sort function in the toolbar. To execute a query
click on the <span class="fa fa-search"></span> button.
</p>
<p>
Sessions can be closed by using the <code>close</code> button under the <code>Actions</code> column and you can
navigate to the connection, consumers and producers by clicking on the appropriate field.
</p>
<p>
Note that each page is loaded in from the broker when navigating to a new page or when a query is executed.
</p>
</div>
</script>
`,
controller: SessionsController
})
.name;
function SessionsController($scope, workspace, jolokia, localStorage, artemisMessage, $location, $timeout, $filter, pagination, artemisConnection, artemisSession, artemisConsumer, artemisProducer) {
var ctrl = this;
ctrl.pagination = pagination;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
ctrl.allSessions = [];
ctrl.sessions = [];
ctrl.pageNumber = 1;
ctrl.workspace = workspace;
ctrl.refreshed = false;
ctrl.sessionToDeletesConnection = '';
ctrl.sessionToDelete = '';
ctrl.closeDialog = false;
ctrl.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'CONNECTION_ID', name: 'Connection ID'},
{id: 'CONSUMER_COUNT', name: 'Consumer Count'},
{id: 'USER', name: 'User'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
sortOptions: [
{id: 'asc', name: 'ascending'},
{id: 'desc', name: 'descending'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortColumn: "id"
},
text: {
fieldText: "Filter Field..",
operationText: "Operation..",
sortOrderText: "ascending",
sortByText: "ID"
}
};
ctrl.tableActionButtons = [
{
name: 'Close',
title: 'Close the Session',
actionFn: openCloseDialog
}
];
ctrl.tableConfig = {
selectionMatchProp: 'id',
showCheckboxes: false
};
ctrl.tableColumns = [
{ header: 'ID', itemField: 'id' },
{ header: 'Connection', itemField: 'connectionID', templateFn: function(value, item) { return '<a href="#" onclick="selectConnection(\'' + item.connectionID + '\')">' + value + '</a>' }},
{ header: 'User', itemField: 'user' },
{ header: 'Consumer Count', itemField: 'consumerCount', templateFn: function(value, item) { return '<a href="#" onclick="selectConsumers(\'' + item.id + '\')">' + value + '</a>' }},
{ header: 'Producer Count', itemField: 'producerCount', templateFn: function(value, item) { return '<a href="#" onclick="selectProducers(\'' + item.id + '\')">' + value + '</a>' }},
{ header: 'Creation Time', itemField: 'creationTime' }
];
ctrl.refresh = function () {
ctrl.refreshed = true;
ctrl.pagination.load();
};
ctrl.reset = function () {
ctrl.filter.values.field = "";
ctrl.filter.values.operation = "";
ctrl.filter.values.value = "";
ctrl.filter.sortOrder = "asc";
ctrl.filter.sortColumn = "id";
ctrl.filter.text.fieldText = "Filter Field..";
ctrl.filter.text.operationText = "Operation..";
ctrl.filter.text.sortOrderText = "ascending";
ctrl.filter.text.sortByText = "ID";
ctrl.refreshed = true;
artemisConnection.connection = null;
artemisSession.session = null;
artemisConsumer.consumer = null;
ctrl.pagination.load();
};
selectConnection = function (connection) {
Artemis.log.info("navigating to connection:" + connection)
artemisSession.session = { connectionID: connection };
$location.path("artemis/artemisConnections");
};
selectConsumers = function (session) {
Artemis.log.info("navigating to consumers:" + session)
artemisConsumer.consumer = { sessionID: session };
$location.path("artemis/artemisConsumers");
};
selectProducers = function (session) {
Artemis.log.info("navigating to producers:" + session)
artemisProducer.producer = { sessionID: session };
$location.path("artemis/artemisProducers");
};
if (artemisConnection.connection) {
Artemis.log.info("navigating to connection = " + artemisConnection.connection.connectionID);
ctrl.filter.values.field = ctrl.filter.fieldOptions[1].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisConnection.connection.connectionID;
}
if (artemisSession.session) {
Artemis.log.info("navigating to session = " + artemisSession.session.session);
ctrl.filter.values.field = ctrl.filter.fieldOptions[0].id;
ctrl.filter.values.operation = ctrl.filter.operationOptions[0].id;
ctrl.filter.values.value = artemisSession.session.session;
}
function openCloseDialog(action, item) {
ctrl.sessionToDelete = item.id;
ctrl.sessionToDeletesConnection = item.connectionID;
ctrl.closeDialog = true;
}
ctrl.closeSession = function () {
Artemis.log.info("closing session: " + ctrl.sessionToDelete);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeSessionWithID(java.lang.String,java.lang.String)',
arguments: [ctrl.sessionToDeletesConnection, ctrl.sessionToDelete] },
Core.onSuccess(ctrl.pagination.load(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close session: " + response);
}}));
}
};
ctrl.loadOperation = function () {
if (mbean) {
var method = 'listSessions(java.lang.String, int, int)';
var sessionsFilter = {
field: ctrl.filter.values.field,
operation: ctrl.filter.values.operation,
value: ctrl.filter.values.value,
sortOrder: ctrl.filter.values.sortOrder,
sortColumn: ctrl.filter.values.sortColumn
};
if (ctrl.refreshed == true) {
ctrl.pagination.reset();
ctrl.refreshed = false;
}
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [JSON.stringify(sessionsFilter), ctrl.pagination.pageNumber, ctrl.pagination.pageSize] }, Core.onSuccess(populateTable, { error: onError }));
}
};
ctrl.pagination.setOperation(ctrl.loadOperation);
function onError(response) {
Core.notification("error", "could not invoke list sessions" + response.error);
$scope.workspace.selectParentNode();
};
function populateTable(response) {
var data = JSON.parse(response.value);
ctrl.sessions = [];
angular.forEach(data["data"], function (value, idx) {
ctrl.sessions.push(value);
});
ctrl.pagination.page(data["count"]);
allSessions = ctrl.sessions;
ctrl.sessions = allSessions;
Core.$apply($scope);
}
ctrl.pagination.load();
}
SessionsController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', 'artemisMessage', '$location', '$timeout', '$filter', 'pagination', 'artemisConnection', 'artemisSession', 'artemisConsumer', 'artemisProducer'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,160 @@
/*
* 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.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis.log.info("loading status");
Artemis._module.component('artemisStatus', {
template:
`<h1>Current Status
<button type="button" class="btn btn-link jvm-title-popover"
uib-popover-template="'status-instructions.html'" popover-placement="bottom-left"
popover-title="Instructions" popover-trigger="'outsideClick'">
<span class="pficon pficon-help"></span>
</button>
</h1>
<div class="container-fluid">
<div class="row">
<div class="col-md-3 text-center">
<label>'Address Memory Used'</label>
<p class="text-left">
<pf-donut-pct-chart config="$ctrl.addressMemoryConfig" data="$ctrl.addressMemoryData" center-label="$ctrl.addressMemoryLabel"></pf-donut-pct-chart>
</p>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
<pf-info-status-card status="$ctrl.infoStatus" show-top-border="true"></pf-info-status-card>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
<pf-info-status-card status="$ctrl.clusterInfoStatus" show-top-border="true"></pf-info-status-card>
</div>
</div>
</div>
<script type="text/ng-template" id="status-instructions.html">
<div>
<p>
This page allows you to view the current status of the broker as well as the status of the cluster it belongs to.
</p>
<p>
It also shows the current address memory usage in relationship to the <code>global-max-size</code>
</p>
<p>Note these metrics update every 5 seconds</p>
</div>
</script>
`,
controller: StatusController
})
.name;
Artemis.log.info("loaded address " + Artemis.addressModule);
function StatusController($scope, workspace, jolokia, localStorage, $interval) {
var ctrl = this;
var mbean = Artemis.getBrokerMBean(workspace, jolokia);
StatusController.prototype.$onInit = function () {
jolokia.request({ type: 'read', mbean: mbean, attribute: 'Version'}, Core.onSuccess(function(response) {
ctrl.infoStatus.info[0] = "version: " + response.value;
}));
jolokia.request({ type: 'read', mbean: mbean, attribute: 'HAPolicy'}, Core.onSuccess(function(response) {
ctrl.clusterInfoStatus.info[2] = "HA Policy: " + response.value;
}));
loadStatus();
ctrl.promise = $interval(function () { return loadStatus(); }, 5000);
};
StatusController.prototype.$onDestroy = function () {
$interval.cancel(this.promise);
};
ctrl.infoStatus = {
"title":"Broker Info",
"href":"#",
"iconClass": "pficon pficon-ok",
"info":[
"version",
"uptime:",
"started:"
]
};
ctrl.clusterInfoStatus = {
"title":"Cluster Info",
"href":"#",
"iconClass": "pficon pficon-ok",
"info":[
"Lives:",
"Backups:",
"HA Policy: :"
]
};
ctrl.addressMemoryConfig = {
'chartId': 'addressMemoryChart',
'units': 'MB',
'thresholds':{'warning':'75','error':'90'}
};
ctrl.addressMemoryData = {
'used': '0',
'total': '1000'
};
ctrl.addressMemoryLabel = "used";
function loadStatus() {
jolokia.request({ type: 'read', mbean: mbean, attribute: 'GlobalMaxSize'}, Core.onSuccess(function(response) { ctrl.addressMemoryData.total = (response.value / 1048576).toFixed(2); }));
jolokia.request({ type: 'read', mbean: mbean, attribute: 'AddressMemoryUsage'}, Core.onSuccess(function(response) { ctrl.addressMemoryData.used = (response.value / 1048576).toFixed(2); }));
jolokia.request({ type: 'read', mbean: mbean, attribute: 'Uptime'}, Core.onSuccess(function(response) {
ctrl.infoStatus.info[1] = "uptime: " + response.value;
}));
jolokia.request({ type: 'read', mbean: mbean, attribute: 'Started'}, Core.onSuccess(function(response) {
ctrl.infoStatus.info[2] = "started: " + response.value;
if(response.value == false) {
ctrl.infoStatus.iconClass = "pficon pficon-error-circle-o";
} else {
ctrl.infoStatus.iconClass = "pficon pficon-ok";
}
}));
var lives = 0;
var backups = 0;
var response = jolokia.request({ type: 'exec', mbean: mbean, operation: 'listNetworkTopology()' }, Core.onSuccess(null));
var responseValue = response.value;
var brokers = angular.fromJson(responseValue);
angular.forEach(brokers, function (broker) {
if (broker.live) {
lives++;
}
if (broker.backup) {
backups++;
}
})
ctrl.clusterInfoStatus.info[0] = "Lives: " + lives;
ctrl.clusterInfoStatus.info[1] = "Backups: " + backups;
if (ctrl.clusterInfoStatus.info[2] == "HA Policy: Replicated") {
jolokia.request({ type: 'read', mbean: mbean, attribute: 'ReplicaSync'}, Core.onSuccess(function(response) {
ctrl.clusterInfoStatus.info[3] = "replicating: " + response.value;
if (response.value == false) {
ctrl.clusterInfoStatus.iconClass = "pficon pficon-error-circle-o";
} else {
ctrl.clusterInfoStatus.iconClass = "pficon pficon-ok";
}
}));
}
}
}
StatusController.$inject = ['$scope', 'workspace', 'jolokia', 'localStorage', '$interval'];
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,191 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference path="tree.component.ts"/>
var Artemis;
(function (Artemis) {
Artemis._module.component('artemisTreeHeader', {
template:
`<div class="tree-nav-sidebar-header">
<form role="form" class="search-pf has-button">
<div class="form-group has-clear">
<div class="search-pf-input-group">
<label for="input-search" class="sr-only">Search Tree:</label>
<input id="input-search" type="search" class="form-control" placeholder="Search tree:"
ng-model="$ctrl.filter">
<button type="button" class="clear" aria-hidden="true"
ng-hide="$ctrl.filter.length === 0"
ng-click="$ctrl.filter = ''">
<span class="pficon pficon-close"></span>
</button>
</div>
</div>
<div class="form-group tree-nav-buttons">
<span class="badge" ng-class="{positive: $ctrl.result.length > 0}"
ng-show="$ctrl.filter.length > 0">
{{$ctrl.result.length}}
</span>
<i class="fa fa-plus-square-o" title="Expand All" ng-click="$ctrl.expandAll()"></i>
<i class="fa fa-minus-square-o" title="Collapse All" ng-click="$ctrl.contractAll()"></i>
</div>
</form>
</div>
`,
controller: TreeHeaderController
})
.component('artemisTree', {
template:
`<div class="tree-nav-sidebar-content">
<div id="artemistree" class="treeview-pf-hover treeview-pf-select"></div>
</div>
`,
controller: TreeController
})
.name;
treeElementId = '#artemistree';
Artemis.log.debug("loaded tree" + Artemis.treeModule);
function TreeHeaderController($scope, $element) {
'ngInject';
Artemis.log.debug("TreeHeaderController ");
this.$scope = $scope;
this.$element = $element;
this.filter = '';
this.result = [];
// it's not possible to declare classes to the component host tag in AngularJS
$element.addClass('tree-nav-sidebar-header');
TreeHeaderController.prototype.$onInit = function () {
Artemis.log.debug("TreeHeaderController init");
var _this = this;
this.$scope.$watch(angular.bind(this, function () { return _this.filter; }), function (filter, previous) {
if (filter !== previous) {
_this.search(filter);
}
});
};
TreeHeaderController.prototype.search = function (filter) {
Artemis.log.debug("TreeHeaderController search");
var _this = this;
var doSearch = function (filter) {
var result = _this.tree().search(filter, {
ignoreCase: true,
exactMatch: false,
revealResults: true
});
_this.result.length = 0;
(_a = _this.result).push.apply(_a, result);
Core.$apply(_this.$scope);
var _a;
};
_.debounce(doSearch, 300, { leading: false, trailing: true })(filter);
};
TreeHeaderController.prototype.tree = function () {
Artemis.log.debug("TreeHeaderController tree");
return $(treeElementId).treeview(true);
};
TreeHeaderController.prototype.expandAll = function () {
Artemis.log.debug("TreeHeaderController expand");
return this.tree()
.expandNode(this.tree().getNodes(), { levels: HawtioTree.getMaxTreeLevel(this.tree()), silent: true });
};
TreeHeaderController.prototype.contractAll = function () {
Artemis.log.debug("TreeHeaderController contract");
return this.tree()
.collapseNode(this.tree().getNodes(), { ignoreChildren: true, silent: true });
};
}
TreeHeaderController.$inject = ['$scope', '$element'];
function TreeController($scope, $location, workspace, $element) {
'ngInject';
this.$scope = $scope;
this.$location = $location;
this.workspace = workspace;
this.$element = $element;
// it's not possible to declare classes to the component host tag in AngularJS
$element.addClass('tree-nav-sidebar-content');
Artemis.log.debug("TreeController ");
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
TreeController.prototype.$onInit = function () {
Artemis.log.debug("TreeController onInit");
var _this = this;
this.$scope.$on('$destroy', function () { return _this.removeTree(); });
this.$scope.$on('$routeChangeStart', function () { return Jmx.updateTreeSelectionFromURL(_this.$location, $(treeElementId)); });
this.$scope.$on('jmxTreeUpdated', function () { return _this.populateTree(); });
this.populateTree();
};
TreeController.prototype.updateSelectionFromURL = function () {
Jmx.updateTreeSelectionFromURLAndAutoSelect(this.$location, $(treeElementId), function (first) {
if (first.children == null) {
return null;
}
// use function to auto select the queue folder on the 1st broker
var queues = first.children[0];
if (queues && queues.text === 'Queue') {
return queues;
}
return null;
}, true);
};
TreeController.prototype.populateTree = function () {
var _this = this;
var children = [];
var tree = this.workspace.tree;
Artemis.log.debug("tree= "+tree);
if (tree) {
var domainName = artemisJmxDomain;
var folder = tree.get(domainName);
if (folder) {
children = folder.children;
}
angular.forEach(children, function(child) {
Artemis.log.debug("child=" + child.text + " " + child.id);
});
var treeElement = $("#artemistree");
this.removeTree();
Jmx.enableTree(this.$scope, this.$location, this.workspace, $(treeElementId), children);
this.updateSelectionFromURL();
}
};
TreeController.prototype.removeTree = function () {
var tree = $(treeElementId).treeview(true);
// There is no exposed API to check whether the tree has already been initialized,
// so let's just check if the methods are presents
if (tree.clearSearch) {
tree.clearSearch();
// Bootstrap tree view leaks the node elements into the data structure
// so let's clean this up when the user leaves the view
var cleanTreeFolder_1 = function (node) {
delete node['$el'];
if (node.nodes)
node.nodes.forEach(cleanTreeFolder_1);
};
cleanTreeFolder_1(this.workspace.tree);
// Then call the tree clean-up method
tree.remove();
}
}
}
TreeController.$inject = ['$scope', '$location', 'workspace', '$element'];
})(Artemis || (Artemis = {}));

View File

@ -1,265 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.ConnectionsController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisConnection, artemisSession) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "connection"
var method = 'listConnections(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'connectionID',
displayName: 'ID',
width: '*'
},
{
field: 'clientID',
displayName: 'Client ID',
width: '*'
},
{
field: 'users',
displayName: 'Users',
width: '*'
},
{
field: 'protocol',
displayName: 'Protocol',
width: '*'
},
{
field: 'sessionCount',
displayName: 'Session Count',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectSessions(row)">{{row.entity.sessionCount}}</a></div>',
sortable: false
},
{
field: 'remoteAddress',
displayName: 'Remote Address',
width: '*'
},
{
field: 'localAddress',
displayName: 'Local Address',
width: '*'
},
{
field: 'creationTime',
displayName: 'Creation Time',
width: '*'
}
];
ARTEMIS.log.debug('sessionStorage: connectionsColumnDefs =', sessionStorage.getItem('connectionsColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('connectionsColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('connectionsColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('connectionsColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'CONNECTION_ID', name: 'Connection ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USERS', name: 'Users'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'SESSION_COUNT', name: 'Session Count'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'SESSION_ID', name: 'Session ID'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "connectionID"
}
};
// Configure Parent/Child click through relationships
if (artemisSession.session) {
$scope.filter.values.field = $scope.filter.fieldOptions[0].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisSession.session.connectionID;
artemisSession.session = null;
}
$scope.selectSessions = function (connection) {
artemisConnection.connection = connection.entity;
$location.path("artemis/sessions");
};
$scope.closeConnection = function () {
var connectionID = $scope.gridOptions.selectedItems[0].connectionID
ARTEMIS.log.info("closing connection: " + connectionID);
if (workspace.selection) {
var mbean = getBrokerMBean(jolokia);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeConnectionWithID(java.lang.String)',
arguments: [connectionID] },
onSuccess($scope.loadTable(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close connection: " + response);
}}));
}
}
};
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["connectionID"],
columns: ["connectionID"],
directions: ["asc"]
};
var refreshed = false;
$scope.showClose = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
$scope.selectGridRow = function () {
$scope.showClose = $scope.gridOptions.selectedItems.length > 0;
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
$scope.gridOptions.selectedItems.length = 0;
$scope.showClose = false;
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,294 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.ConsumersController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisConnection, artemisSession, artemisConsumer, artemisQueue, artemisAddress) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "consumer";
var method = 'listConsumers(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'id',
displayName: 'ID',
width: '*'
},
{
field: 'session',
displayName: 'Session',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectSession(row)">{{row.entity.session}}</a></div>'
},
{
field: 'clientID',
displayName: 'Client ID',
width: '*'
},
{
field: 'protocol',
displayName: 'Protocol',
width: '*'
},
{
field: 'queue',
displayName: 'Queue',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectQueue(row)">{{row.entity.queue}}</a></div>'
},
{
field: 'queueType',
displayName: 'Queue Type',
width: '*'
},
{
field: 'filter',
displayName: 'Filter',
width: '*'
},
{
field: 'address',
displayName: 'Address',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectAddress(row)">{{row.entity.address}}</a></div>'
},
{
field: 'remoteAddress',
displayName: 'Remote Address',
width: '*'
},
{
field: 'localAddress',
displayName: 'Local Address',
width: '*'
},
{
field: 'creationTime',
displayName: 'Creation Time',
width: '*'
}
];
ARTEMIS.log.debug('sessionStorage: consumersColumnDefs =', sessionStorage.getItem('consumersColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('consumersColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('consumersColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('consumersColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'SESSION_ID', name: 'Session ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USER', name: 'User'},
{id: 'ADDRESS', name: 'Address'},
{id: 'QUEUE', name: 'Queue'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "id"
}
};
$scope.selectSession = function (row) {
artemisConsumer.consumer = row.entity;
$location.path("artemis/sessions");
};
$scope.selectQueue = function (row) {
artemisQueue.queue = row.entity;
$location.path("artemis/queues");
};
$scope.selectAddress = function (row) {
artemisAddress.address = row.entity;
$location.path("artemis/addresses");
};
// Configure Parent/Child click through relationships
if (artemisSession.session) {
$scope.filter.values.field = $scope.filter.fieldOptions[1].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisSession.session.id;
artemisSession.session = null;
}
artemisSession.session = null;
$scope.closeConsumer = function () {
var consumerID = $scope.gridOptions.selectedItems[0].id;
var sessionID = $scope.gridOptions.selectedItems[0].session;
ARTEMIS.log.info("closing session: " + sessionID);
if (workspace.selection) {
var mbean = getBrokerMBean(jolokia);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeConsumerWithID(java.lang.String, java.lang.String)',
arguments: [sessionID, consumerID] },
onSuccess($scope.loadTable(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close consumer: " + response);
}}));
}
}
};
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["id"],
columns: ["id"],
directions: ["asc"]
};
var refreshed = false;
$scope.showClose = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
$scope.selectGridRow = function () {
$scope.showClose = $scope.gridOptions.selectedItems.length > 0;
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
$scope.gridOptions.selectedItems.length = 0;
$scope.showClose = false;
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,62 +0,0 @@
/*
* 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.
*/
var ARTEMIS;
(function (ARTEMIS) {
ARTEMIS.jmsHeaderSchema = {
definitions: {
headers: {
properties: {
JMSCorrelationID: {
type: "java.lang.String"
},
JMSDeliveryMode: {
"type": "string",
"enum": [
"PERSISTENT",
"NON_PERSISTENT"
]
},
JMSDestination: {
type: "javax.jms.Destination"
},
JMSExpiration: {
type: "long"
},
JMSPriority: {
type: "int"
},
JMSReplyTo: {
type: "javax.jms.Destination"
},
JMSType: {
type: "java.lang.String"
},
JMSXGroupId: {
type: "java.lang.String"
},
_AMQ_SCHED_DELIVERY: {
type: "java.lang.String"
}
}
},
"javax.jms.Destination": {
type: "java.lang.String"
}
}
};
})(ARTEMIS || (ARTEMIS = {}));
//# sourceMappingURL=jmsHeaderSchema.js.map

View File

@ -1,54 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
/**
* @method PreferencesController
* @param $scope
*
* Controller for the Preferences interface
*/
ARTEMIS.PreferencesController = function ($scope, localStorage, userDetails, $rootScope) {
Core.initPreferenceScope($scope, localStorage, {
'artemisUserName': {
'value': userDetails.username
},
'artemisPassword': {
'value': userDetails.password
},
'artemisDLQ': {
'value': "DLQ"
},
'artemisExpiryQueue': {
'value': "ExpiryQueue"
},
'artemisBrowseBytesMessages': {
'value': 1,
'converter': parseInt,
'formatter': function (value) {
return "" + value;
}
}
});
};
return ARTEMIS;
}(ARTEMIS || {}));

View File

@ -1,254 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.ProducersController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisAddress, artemisSession, artemisProducer) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "producer";
var method = 'listProducers(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'id',
displayName: 'ID',
width: '*'
},
{
field: 'session',
displayName: 'Session',
width: '*',
sortable: false,
cellTemplate: '<div class="ngCellText"><a ng-click="selectSession(row)">{{row.entity.session}}</a></div>'
},
{
field: 'clientID',
displayName: 'Client ID',
sortable: false,
width: '*'
},
{
field: 'protocol',
displayName: 'Protocol',
width: '*',
sortable: false
},
{
field: 'user',
displayName: 'User',
width: '*',
sortable: false
},
{
field: 'address',
displayName: 'Address',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectAddress(row)">{{row.entity.address}}</a></div>'
},
{
field: 'remoteAddress',
displayName: 'Remote Address',
width: '*',
sortable: false
},
{
field: 'localAddress',
displayName: 'Local Address',
width: '*',
sortable: false
}
];
ARTEMIS.log.debug('sessionStorage: producersColumnDefs =', sessionStorage.getItem('producersColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('producersColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('producersColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('producersColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'SESSION_ID', name: 'Session ID'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'USER', name: 'User'},
{id: 'ADDRESS', name: 'Address'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'}
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "id"
}
};
$scope.selectAddress = function (row) {
artemisAddress.address = row.entity;
$location.path("artemis/addresses");
};
$scope.selectSession = function (row) {
artemisProducer.producer = row.entity;
$location.path("artemis/sessions");
};
// Configure Parent/Child click through relationships
if (artemisSession.session) {
$scope.filter.values.field = $scope.filter.fieldOptions[1].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisSession.session.id;
artemisSession.session = null;
}
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["id"],
columns: ["id"],
directions: ["asc"]
};
var refreshed = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,152 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
/**
* @method QueueController
* @param $scope
* @param ARTEMISService
*
* Controller for the Create interface
*/
ARTEMIS.QueueController = function ($scope, workspace, ARTEMISService, jolokia, localStorage) {
Core.initPreferenceScope($scope, localStorage, {
'durable': {
'value': true,
'converter': Core.parseBooleanValue
},
'routingType': {
'value': 0,
'converter': parseInt,
'formatter': parseInt
},
'maxConsumers': {
'value': -1,
'converter': parseInt,
'formatter': parseInt
},
'purgeWhenNoConsumers': {
'value': false,
'converter': Core.parseBooleanValue
}
});
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
$scope.workspace = workspace;
$scope.message = "";
$scope.queueType = 'true';
$scope.deleteDialog = false;
$scope.purgeDialog = false;
$scope.$watch('workspace.selection', function () {
workspace.moveIfViewInvalid();
});
function operationSuccess() {
$scope.queueName = "";
$scope.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
$scope.workspace.loadTree();
}
function deleteSuccess() {
// lets set the selection to the parent
workspace.removeAndSelectParentNode();
$scope.workspace.operationCounter += 1;
Core.$apply($scope);
Core.notification("success", $scope.message);
$scope.workspace.loadTree();
}
$scope.createQueue = function (queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers) {
var mbean = getBrokerMBean(jolokia);
if (mbean) {
var selection = workspace.selection;
var entries = selection.entries;
var address = entries["address"];
if (address.charAt(0) === '"' && address.charAt(address.length -1) === '"')
{
address = address.substr(1,address.length -2);
}
$scope.message = "Created queue " + queueName + " durable=" + durable + " filter=" + filter + " on address " + address;
if (routingType == 0) {
ARTEMIS.log.info($scope.message);
ARTEMISService.artemisConsole.createQueue(mbean, jolokia, address, "MULTICAST", queueName, durable, filter, maxConsumers, purgeWhenNoConsumers, onSuccess(operationSuccess));
ARTEMIS.log.info("executed");
} else {
ARTEMIS.log.info($scope.message);
ARTEMISService.artemisConsole.createQueue(mbean, jolokia, address, "ANYCAST", queueName, durable, filter, maxConsumers, purgeWhenNoConsumers, onSuccess(operationSuccess));
ARTEMIS.log.info("executed");
}
}
};
$scope.deleteDestination = function (isQueue) {
var selection = workspace.selection;
var entries = selection.entries;
var mbean = getBrokerMBean(jolokia);
ARTEMIS.log.info(mbean);
if (mbean) {
if (selection && jolokia && entries) {
var domain = selection.domain;
var name = entries["Destination"] || entries["destinationName"] || selection.title;
name = ARTEMISService.artemisConsole.ownUnescape(name);
ARTEMIS.log.info(name);
var operation;
if (isQueue) {
$scope.message = "Deleted queue " + name;
ARTEMISService.artemisConsole.deleteQueue(mbean, jolokia, name, onSuccess(deleteSuccess));
}
else {
$scope.message = "Deleted topic " + name;
ARTEMISService.artemisConsole.deleteTopic(mbean, jolokia, name, onSuccess(deleteSuccess));
}
}
}
};
$scope.purgeDestination = function () {
var selection = workspace.selection;
var entries = selection.entries;
var mbean = selection.objectName;
if (mbean) {
if (selection && jolokia && entries) {
var name = entries["Destination"] || entries["destinationName"] || selection.title;
name = name.unescapeHTML();
var operation = "purge()";
$scope.message = "Purged queue " + name;
ARTEMISService.artemisConsole.purgeQueue(mbean, jolokia, onSuccess(deleteSuccess));
}
}
};
$scope.name = function () {
var selection = workspace.selection;
if (selection) {
return ARTEMISService.artemisConsole.ownUnescape(selection.title);
}
return null;
};
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
}
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,345 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.QueuesController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisConnection, artemisSession, artemisQueue, artemisAddress) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "queue";
var method = 'listQueues(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'manage',
displayName: 'manage',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="navigateToQueueAtts(row)">attributes</a>&nbsp;<a ng-click="navigateToQueueOps(row)">operations</a></div>'
},
{
field: 'id',
displayName: 'ID',
width: '*'
},
{
field: 'name',
displayName: 'Name',
width: '*',
cellTemplate: '<div class="ngCellText" title="{{row.entity.name}}">{{row.entity.name}}</div>'
},
{
field: 'address',
displayName: 'Address',
width: '*',
cellTemplate: '<div class="ngCellText" title="{{row.entity.address}}"><a ng-click="selectAddress(row)">{{row.entity.address}}</a></div>'
},
{
field: 'routingType',
displayName: 'Routing Type',
width: '*'
},
{
field: 'filter',
displayName: 'Filter',
width: '*',
cellTemplate: '<div class="ngCellText" title="{{row.entity.filter}}">{{row.entity.filter}}</div>'
},
{
field: 'durable',
displayName: 'Durable',
width: '*'
},
{
field: 'maxConsumers',
displayName: 'Max Consumers',
width: '*'
},
{
field: 'purgeOnNoConsumers',
displayName: 'Purge On No Consumers',
width: '*'
},
{
field: 'consumerCount',
displayName: 'Consumer Count',
width: '*'
},
{
field: 'rate',
displayName: 'Rate',
width: '*'
},
{
field: 'messageCount',
displayName: 'Message Count',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="navigateToBrowseQueue(row)">{{row.entity.messageCount}}</a></div>'
},
// Hidden
{
field: 'paused',
displayName: 'Paused',
width: '*',
visible: false
},
{
field: 'temporary',
displayName: 'Temporary',
width: '*',
visible: false
},
{
field: 'autoCreated',
displayName: 'Auto Created',
width: '*',
visible: false
},
{
field: 'user',
displayName: 'User',
width: '*',
visible: false
},
{
field: 'messagesAdded',
displayName: 'Total Messages Added',
width: '*',
visible: false
},
{
field: 'messagesAcked',
displayName: 'Total Messages Acked',
width: '*',
visible: false
},
{
field: 'deliveringCount',
displayName: 'Delivering Count',
width: '*',
visible: false
},
{
field: 'messagesKilled',
displayName: 'Messages Killed',
width: '*',
visible: false
},
{
field: 'directDeliver',
displayName: 'Direct Deliver',
width: '*',
visible: false
}
];
ARTEMIS.log.debug('sessionStorage: queuesColumnDefs =', sessionStorage.getItem('queuesColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('queuesColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('queuesColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('queuesColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'NAME', name: 'Name'},
{id: 'CONSUMER_ID', name: 'Consumer ID'},
{id: 'ADDRESS', name: 'Address'},
{id: 'FILTER', name: 'Filter'},
{id: 'MAX_CONSUMERS', name: 'maxConsumers'},
{id: 'ROUTING_TYPE', name: 'Routing Type'},
{id: 'PURGE_ON_NO_CONSUMERS', name: 'Purge On No Consumers'},
{id: 'USER', name: 'User'},
{id: 'MESSAGE_COUNT', name: 'Message Count'},
{id: 'DELIVERING_COUNT', name: 'Delivering Count'},
{id: 'PAUSED', name: 'Paused'},
{id: 'TEMPORARY', name: 'Temporary'},
{id: 'AUTO_CREATED', name: 'Auto Created'},
{id: 'RATE', name: 'Rate'},
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "id"
}
};
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
if (artemisAddress.address) {
$scope.filter.values.field = $scope.filter.fieldOptions[3].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisAddress.address.name;
artemisAddress.address = null;
}
if (artemisQueue.queue) {
$scope.filter.values.field = $scope.filter.fieldOptions[1].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisQueue.queue.queue;
artemisQueue.queue = null;
}
artemisSession.session = null;
$scope.navigateToQueueAtts = function (row) {
$location.path("jmx/attributes").search({"tab": "artemis", "nid": ARTEMIS.getQueueNid(row.entity, $location)});
};
$scope.navigateToQueueOps = function (row) {
$location.path("jmx/operations").search({"tab": "artemis", "nid": ARTEMIS.getQueueNid(row.entity, $location)});
};
$scope.navigateToBrowseQueue = function (row) {
$location.path("artemis/browseQueue").search({"tab": "artemis", "nid": ARTEMIS.getQueueNid(row.entity, $location)});
};
$scope.selectAddress = function (row) {
artemisAddress.address = row.entity;
$location.path("artemis/addresses");
};
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["id"],
columns: ["id"],
directions: ["asc"]
};
var refreshed = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,210 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS;
(function (ARTEMIS) {
var DELIVERY_PERSISTENT = "2";
ARTEMIS.SendMessageController = function($route, $scope, $element, $timeout, workspace, ARTEMISService, jolokia, localStorage, $location, artemisMessage) {
Core.initPreferenceScope($scope, localStorage, {
'durable': {
'value': true,
'converter': Core.parseBooleanValue
}
});
var log = Logger.get("ARTEMIS");
$scope.noCredentials = false;
$scope.showChoose = false;
$scope.profileFileNames = [];
$scope.profileFileNameToProfileId = {};
$scope.selectedFiles = {};
$scope.container = {};
$scope.message = "\n\n\n\n";
$scope.headers = [];
// bind model values to search params...
Core.bindModelToSearchParam($scope, $location, "tab", "subtab", "compose");
Core.bindModelToSearchParam($scope, $location, "searchText", "q", "");
// only reload the page if certain search parameters change
Core.reloadWhenParametersChange($route, $scope, $location);
$scope.checkCredentials = function () {
$scope.noCredentials = (Core.isBlank(localStorage['artemisUserName']) || Core.isBlank(localStorage['artemisPassword']));
};
if ($location.path().has('artemis')) {
$scope.localStorage = localStorage;
$scope.$watch('localStorage.artemisUserName', $scope.checkCredentials);
$scope.$watch('localStorage.artemisPassword', $scope.checkCredentials);
//prefill if it's a resent
if (artemisMessage.message !== null) {
$scope.message = artemisMessage.message.bodyText;
if (artemisMessage.message.PropertiesText !== null) {
for (var p in artemisMessage.message.StringProperties) {
$scope.headers.push({name: p, value: artemisMessage.message.StringProperties[p]});
}
}
}
// always reset at the end
artemisMessage.message = null;
}
$scope.openPrefs = function () {
$location.search('pref', 'Artemis');
$scope.$emit("hawtioOpenPrefs");
};
var LANGUAGE_FORMAT_PREFERENCE = "defaultLanguageFormat";
var sourceFormat = workspace.getLocalStorage(LANGUAGE_FORMAT_PREFERENCE) || "javascript";
// TODO Remove this if possible
$scope.codeMirror = undefined;
var options = {
mode: {
name: sourceFormat
},
// Quick hack to get the codeMirror instance.
onChange: function (codeMirror) {
if (!$scope.codeMirror) {
$scope.codeMirror = codeMirror;
}
}
};
$scope.codeMirrorOptions = CodeEditor.createEditorSettings(options);
$scope.addHeader = function () {
$scope.headers.push({name: "", value: ""});
// lets set the focus to the last header
if ($element) {
$timeout(function () {
var lastHeader = $element.find("input.headerName").last();
lastHeader.focus();
}, 100);
}
};
$scope.removeHeader = function (header) {
$scope.headers = $scope.headers.remove(header);
};
$scope.defaultHeaderNames = function () {
var answer = [];
function addHeaderSchema(schema) {
angular.forEach(schema.definitions.headers.properties, function (value, name) {
answer.push(name);
});
}
if (isJmsEndpoint()) {
addHeaderSchema(ARTEMIS.jmsHeaderSchema);
}
/*if (isARTEMISEndpoint()) {
addHeaderSchema(ARTEMIS.ARTEMISHeaderSchema);
}*/
return answer;
};
/* save the sourceFormat in preferences for later
* Note, this would be controller specific preferences and not the global, overriding, preferences */
// TODO Use ng-selected="changeSourceFormat()" - Although it seemed to fire multiple times..
$scope.$watch('codeMirrorOptions.mode.name', function (newValue, oldValue) {
workspace.setLocalStorage(LANGUAGE_FORMAT_PREFERENCE, newValue);
});
var sendWorked = function () {
Core.notification("success", "Message sent!");
};
$scope.autoFormat = function () {
setTimeout(function () {
CodeEditor.autoFormatEditor($scope.codeMirror);
}, 50);
};
$scope.sendMessage = function (durable) {
var body = $scope.message;
ARTEMIS.log.info(body);
doSendMessage(durable, body, sendWorked);
};
function doSendMessage(durable, body, onSendCompleteFn) {
var selection = workspace.selection;
if (selection) {
var mbean = selection.objectName;
if (mbean) {
var headers = null;
if ($scope.headers.length) {
headers = {};
angular.forEach($scope.headers, function (object) {
var key = object.name;
if (key) {
headers[key] = object.value;
}
});
log.info("About to send headers: " + JSON.stringify(headers));
}
var callback = onSuccess(onSendCompleteFn);
ARTEMIS.log.info("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
var user = localStorage["artemisUserName"];
var pwd = localStorage["artemisPassword"];
// AMQ is sending non persistent by default, so make sure we tell to sent persistent by default
if (!headers) {
headers = {};
}
var type = 3;
ARTEMISService.artemisConsole.sendMessage(mbean, jolokia, headers, type, body, durable, user, pwd, callback, onSuccess(callback));
}
}
}
$scope.fileSelection = function () {
var answer = [];
angular.forEach($scope.selectedFiles, function (value, key) {
if (value) {
answer.push(key);
}
});
return answer;
};
$scope.sendSelectedFiles = function () {
var filesToSend = $scope.fileSelection();
var fileCount = filesToSend.length;
var version = $scope.container.versionId || "1.0";
function onSendFileCompleted(response) {
if (filesToSend.length) {
var fileName = filesToSend.pop();
if (fileName) {
// lets load the file data...
var profile = $scope.profileFileNameToProfileId[fileName];
if (profile) {
var body = Fabric.getConfigFile(jolokia, version, profile, fileName);
if (!body) {
log.warn("No body for message " + fileName);
body = "";
}
doSendMessage(body, onSendFileCompleted);
}
}
}
else {
var text = Core.maybePlural(fileCount, "Message") + " sent!";
Core.notification("success", text);
}
}
// now lets start sending
onSendFileCompleted(null);
};
function isJmsEndpoint() {
// TODO check for the jms/activemq endpoint in ARTEMIS or if its an activemq endpoint
return true;
}
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Artemis;
(function (Artemis) {
Artemis._module.factory('pagination',
function () {
return {
pageSizeOptions: [10,20,50,100],
pageSize: 10,
pageNumber: 1,
totalItems: 1,
firstItem: 1,
lastItem: 1,
pages: 1,
page: function (resultsSize) {
this.totalItems = resultsSize;
this.firstItem = this.pageNumber * this.pageSize - this.pageSize + 1;
this.lastItem = this.firstItem + this.pageSize - 1;
if (this.lastItem > this.totalItems) {
this.lastItem = this.totalItems;
}
this.pages = Math.ceil(this.totalItems/this.pageSize);
},
nextPage: function () {
this.pageNumber++;
this.load();
},
previousPage: function () {
this.pageNumber--;
this.load();
},
lastPage: function () {
this.pageNumber = this.pages;
this.load();
},
firstPage: function () {
this.pageNumber = 1;
this.load();
},
reset: function () {
this.pageNumber = 1;
},
load: function () {},
setOperation: function (operation) {
this.load = operation;
}
}
}).run(configurePagination);
function configurePagination($templateCache) {
$templateCache.put('plugin/artemispagination.html',
`
<div ng_show="$ctrl.pagination.totalItems > 0">
<form class="content-view-pf-pagination table-view-pf-pagination clearfix" id="pagination1">
<div class="form-group">
<select ng-model="$ctrl.pagination.pageSize" ng-options="qn for qn in $ctrl.pagination.pageSizeOptions" id="pagination.values.pageSize">
</select>
<span>per page</span>
</div>
<div class="form-group">
<span><span class="pagination-pf-items-current">{{$ctrl.pagination.firstItem}}-{{$ctrl.pagination.lastItem}}</span> of <span class="pagination-pf-items-total">{{$ctrl.pagination.totalItems}}</span></span>
<ul class="pagination pagination-pf-back">
<li class="{{$ctrl.pagination.pageNumber == 1 ? 'disabled' : ''}}"><a href="#" title="First Page" ng-click="$ctrl.pagination.pageNumber != 1 && $ctrl.pagination.firstPage()"><span class="i fa fa-angle-double-left"></span></a></li>
<li class="{{$ctrl.pagination.pageNumber == 1 ? 'disabled' : ''}}"><a href="#" title="Previous Page" ng-click="$ctrl.pagination.pageNumber != 1 && $ctrl.pagination.previousPage()"><span class="i fa fa-angle-left"></span></a></li>
</ul>
<label for="pagination1-page" class="sr-only">Current Page</label>
<input class="pagination-pf-page" type="text" value="{{$ctrl.pagination.pageNumber}}" id="pagination1-page" on-change="$ctrl.firstPage()"/>
<span>of <span class="pagination-pf-pages">{{$ctrl.pagination.pages}}</span></span>
<ul class="pagination pagination-pf-forward">
<li class="{{$ctrl.pagination.pageNumber == $ctrl.pagination.pages ? 'disabled' : ''}}"><a href="#" title="Next Page" ng-click="$ctrl.pagination.pageNumber != $ctrl.pagination.pages && $ctrl.pagination.nextPage()"><span class="i fa fa-angle-right"></span></a></li>
<li class="{{$ctrl.pagination.pageNumber == $ctrl.pagination.pages ? 'disabled' : ''}}"><a href="#" title="Last Page" ng-click="$ctrl.pagination.pageNumber != $ctrl.pagination.pages && $ctrl.pagination.lastPage()"><span class="i fa fa-angle-double-right"></span></a></li>
</ul>
</div>
</form>
</div>
`
)
}
configurePagination.$inject = ['$templateCache'];
})(Artemis || (Artemis = {}));

View File

@ -14,30 +14,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#main-nav > .navbar-inner.main-nav-upper > .container > .pull-left > .brand {
/*
padding-top: 6px;
*/
white-space: nowrap;
}
var Artemis;
(function (Artemis) {
Artemis._module.factory('artemisMessage', function () {
return { 'message': null };
})
.factory('artemisConnection', function () {
return { 'connection': null };
})
.factory('artemisSession', function () {
return { 'session': null };
})
.factory('artemisConsumer', function () {
return { 'consumer': null };
})
.factory('artemisProducer', function () {
return { 'producer': null };
})
.factory('artemisQueue', function () {
return { 'queue': null };
})
.factory('artemisAddress', function () {
return { 'address': null };
});
#main-nav > .navbar-inner.main-nav-upper > .container > .pull-left > .brand > img {
display: inline-block;
position: relative;
left: -3px;
height: 58px;
}
#main-nav > .navbar-inner.main-nav-upper > .container > .pull-left > .brand > strong {
font-weight: bold;
font-size: 17px;
position: relative;
top: 6px;
left: 0;
}
.brand > .with-text {
margin-top: 0;
}
})(Artemis || (Artemis = {}));

View File

@ -0,0 +1,116 @@
/*
* 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.
*/
var Artemis;
(function (Artemis) {
Artemis._module.run(configureToolbar);
function configureToolbar($templateCache) {
$templateCache.put('plugin/artemistoolbar.html',
`
<div class="row toolbar-pf table-view-pf-toolbar" id="toolbar1">
<form class="toolbar-pf-actions">
<div class="form-group toolbar-pf-filter">
<div class="input-group">
<div class="input-group-btn">
<button id="filter.values.field" type="button" class="btn btn-default dropdown-toggle" id="filter" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{$ctrl.filter.text.fieldText}} <span class="caret"></span></button>
<ul class="dropdown-menu">
<li ng-repeat="option in $ctrl.filter.fieldOptions"
id="option.id" ng-click="$ctrl.filter.values.field = option.id;$ctrl.filter.text.fieldText = option.name">{{ option.name }}</ul>
</ul>
</div>
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" id="filter" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{$ctrl.filter.text.operationText}}<span class="caret"></span></button>
<ul class="dropdown-menu">
<li ng-repeat="option in $ctrl.filter.operationOptions"
id="option.id" ng-click="$ctrl.filter.values.operation = option.id;$ctrl.filter.text.operationText = option.name">{{ option.name }}</ul>
</ul>
</div>
<input type="text" class="form-control" ng-model="$ctrl.filter.values.value" placeholder="Value" autocomplete="off" id="filterInput">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" id="filter" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{$ctrl.filter.text.sortOrderText}}<span class="caret"></span></button>
<ul class="dropdown-menu">
<li ng-repeat="option in $ctrl.filter.sortOptions"
id="option.id" ng-click="$ctrl.filter.values.sortOrder = option.id;$ctrl.filter.text.sortOrderText = option.name">{{ option.name }}</ul>
</ul>
</div>
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" id="filter" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{$ctrl.filter.text.sortByText}}<span class="caret"></span></button>
<ul class="dropdown-menu">
<li ng-repeat="option in $ctrl.filter.fieldOptions"
id="option.id" ng-click="$ctrl.filter.values.sortColumn = option.id;$ctrl.filter.text.sortByText = option.name">{{ option.name }}</ul>
</ul>
</div>
<div class="input-group-btn">
<button class="btn btn-link btn-find" ng-click="$ctrl.refresh()" type="button">
&nbsp;&nbsp;<span class="fa fa-search"></span>&nbsp;&nbsp;
</button>
</div>
<div class="input-group-btn">
<button class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-click="$ctrl.reset()">Reset
</button>
</div>
</div>
</form>
</div>
`
)
$templateCache.put('plugin/artemismessagetoolbar.html',
`
<div class="row toolbar-pf table-view-pf-toolbar" id="toolbar1">
<div class="col-sm-20">
<form class="toolbar-pf-actions">
<div class="form-group toolbar-pf-filter">
<div class="input-group">
<input type="text" class="form-control" ng-model="$ctrl.filter.values.value" placeholder="Filter..." autocomplete="off" id="filterInput">
<div class="input-group-btn">
<button class="btn btn-link btn-find" ng-click="$ctrl.refresh()" type="button">
&nbsp;&nbsp;<span class="fa fa-search"></span>&nbsp;&nbsp;
</button>
</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-click="$ctrl.reset()">Reset
</button>
<button ng-show="$ctrl.dlq" class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-click="$ctrl.retry()">Retry Messages
</button>
<button ng-show="$ctrl.dlq" class="btn btn-default primary-action ng-binding ng-scope"
type="button"
title=""
ng-click="$ctrl.retry()">Move Messages
</button>
</div>
</form>
</div>
</div>
`
)
}
configureToolbar.$inject = ['$templateCache'];
})(Artemis || (Artemis = {}));

View File

@ -1,284 +0,0 @@
/*
* 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.
*/
/**
* @module ARTEMIS
*/
var ARTEMIS = (function(ARTEMIS) {
ARTEMIS.SessionsController = function ($scope, $location, workspace, ARTEMISService, jolokia, localStorage, artemisConnection, artemisSession, artemisConsumer, artemisProducer) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
/**
* Required For Each Object Type
*/
var objectType = "sessions"
var method = 'listSessions(java.lang.String, int, int)';
var defaultAttributes = [
{
field: 'id',
displayName: 'ID',
width: '*'
},
{
field: 'connectionID',
displayName: 'Connection',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectConnection(row)">{{row.entity.connectionID}}</a></div>'
},
{
field: 'user',
displayName: 'User',
width: '*'
},
{
field: 'consumerCount',
displayName: 'Consumer Count',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectConsumers(row)">{{row.entity.consumerCount}}</a></div>'
},
{
field: 'producerCount',
displayName: 'Producer Count',
width: '*',
cellTemplate: '<div class="ngCellText"><a ng-click="selectProducers(row)">{{row.entity.producerCount}}</a></div>'
},
{
field: 'creationTime',
displayName: 'Creation Time',
width: '*'
},
];
ARTEMIS.log.debug('sessionStorage: sessionsColumnDefs =', sessionStorage.getItem('sessionsColumnDefs'));
var attributes = defaultAttributes;
if (sessionStorage.getItem('sessionsColumnDefs')) {
attributes = JSON.parse(sessionStorage.getItem('sessionsColumnDefs'));
}
$scope.$on('ngGridEventColumns', function (newColumns) {
ARTEMIS.log.debug('ngGridEventColumns:', newColumns);
var visibles = newColumns.targetScope.columns.reduce(function (visibles, column) {
visibles[column.field] = column.visible;
return visibles;
}, {});
ARTEMIS.log.debug('ngGridEventColumns: visibles =', visibles);
attributes.forEach(function (attribute) {
attribute.visible = visibles[attribute.field];
});
sessionStorage.setItem('sessionsColumnDefs', JSON.stringify(attributes));
});
$scope.filter = {
fieldOptions: [
{id: 'ID', name: 'ID'},
{id: 'CONNECTION_ID', name: 'Connection ID'},
{id: 'CONSUMER_COUNT', name: 'Consumer Count'},
{id: 'USER', name: 'User'},
{id: 'PROTOCOL', name: 'Protocol'},
{id: 'CLIENT_ID', name: 'Client ID'},
{id: 'LOCAL_ADDRESS', name: 'Local Address'},
{id: 'REMOTE_ADDRESS', name: 'Remote Address'},
],
operationOptions: [
{id: 'EQUALS', name: 'Equals'},
{id: 'CONTAINS', name: 'Contains'},
{id: 'GREATER_THAN', name: 'Greater Than'},
{id: 'LESS_THAN', name: 'Less Than'}
],
values: {
field: "",
operation: "",
value: "",
sortOrder: "asc",
sortBy: "id"
}
};
// Configure Parent/Child click through relationships
$scope.selectConnection = function (row) {
artemisSession.session = row.entity;
$location.path("artemis/connections");
};
$scope.selectProducers = function (row) {
artemisSession.session = row.entity;
$location.path("artemis/producers");
};
$scope.selectConsumers = function (row) {
artemisSession.session = row.entity;
$location.path("artemis/consumers");
};
if (artemisConnection.connection) {
ARTEMIS.log.info("navigating to connection = " + artemisConnection.connection.connectionID);
$scope.filter.values.field = $scope.filter.fieldOptions[1].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisConnection.connection.connectionID;
}
if (artemisConsumer.consumer) {
ARTEMIS.log.info("navigating to consumer = " + artemisConsumer.consumer.ID);
$scope.filter.values.field = $scope.filter.fieldOptions[0].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisConsumer.consumer.session;
}
if (artemisProducer.producer) {
ARTEMIS.log.info("navigating to producer = " + artemisProducer.producer.ID);
$scope.filter.values.field = $scope.filter.fieldOptions[0].id;
$scope.filter.values.operation = $scope.filter.operationOptions[0].id;
$scope.filter.values.value = artemisProducer.producer.session;
}
//refresh after use
artemisSession.connection = null;
artemisConsumer.consumer = null;
artemisProducer.producer = null;
$scope.closeSession = function () {
var sessionID = $scope.gridOptions.selectedItems[0].id;
var connectionID = $scope.gridOptions.selectedItems[0].connectionID;
ARTEMIS.log.info("closing session: " + sessionID);
if (workspace.selection) {
var mbean = getBrokerMBean(jolokia);
if (mbean) {
jolokia.request({ type: 'exec',
mbean: mbean,
operation: 'closeSessionWithID(java.lang.String, java.lang.String)',
arguments: [connectionID, sessionID] },
onSuccess($scope.loadTable(), { error: function (response) {
Core.defaultJolokiaErrorHandler("Could not close session: " + response);
}}));
}
}
};
/**
* Below here is utility.
*
* TODO Refactor into new separate files
*/
$scope.workspace = workspace;
$scope.objects = [];
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [50, 100, 200],
pageSize: 100,
currentPage: 1
};
$scope.sortOptions = {
fields: ["id"],
columns: ["id"],
directions: ["asc"]
};
var refreshed = false;
$scope.showClose = false;
$scope.gridOptions = {
selectedItems: [],
data: 'objects',
showFooter: true,
showFilter: true,
showColumnMenu: true,
enableCellSelection: false,
enableHighlighting: true,
enableColumnResize: true,
enableColumnReordering: true,
selectWithCheckboxOnly: false,
showSelectionCheckbox: false,
multiSelect: false,
displaySelectionCheckbox: false,
pagingOptions: $scope.pagingOptions,
enablePaging: true,
totalServerItems: 'totalServerItems',
maintainColumnRatios: false,
columnDefs: attributes,
enableFiltering: true,
useExternalFiltering: true,
sortInfo: $scope.sortOptions,
useExternalSorting: true,
};
$scope.refresh = function () {
refreshed = true;
$scope.loadTable();
};
$scope.reset = function () {
$scope.filter.values.field = "";
$scope.filter.values.operation = "";
$scope.filter.values.value = "";
$scope.loadTable();
};
$scope.loadTable = function () {
$scope.filter.values.sortColumn = $scope.sortOptions.fields[0];
$scope.filter.values.sortBy = $scope.sortOptions.directions[0];
$scope.filter.values.sortOrder = $scope.sortOptions.directions[0];
var mbean = getBrokerMBean(jolokia);
if (mbean.includes("undefined")) {
onBadMBean();
} else if (mbean) {
var filter = JSON.stringify($scope.filter.values);
console.log("Filter string: " + filter);
jolokia.request({ type: 'exec', mbean: mbean, operation: method, arguments: [filter, $scope.pagingOptions.currentPage, $scope.pagingOptions.pageSize] }, onSuccess(populateTable, { error: onError }));
}
};
$scope.selectGridRow = function () {
$scope.showClose = $scope.gridOptions.selectedItems.length > 0;
};
function onError() {
Core.notification("error", "Could not retrieve " + objectType + " list from Artemis.");
}
function onBadMBean() {
Core.notification("error", "Could not retrieve " + objectType + " list. Wrong MBean selected.");
}
function populateTable(response) {
$scope.gridOptions.selectedItems.length = 0;
$scope.showClose = false;
var data = JSON.parse(response.value);
$scope.objects = [];
angular.forEach(data["data"], function (value, idx) {
$scope.objects.push(value);
});
$scope.totalServerItems = data["count"];
if (refreshed == true) {
$scope.gridOptions.pagingOptions.currentPage = 1;
refreshed = false;
}
Core.$apply($scope);
}
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.loadTable();
}
}, true);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (parseInt(newVal.currentPage) && newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.loadTable();
}
if (parseInt(newVal.pageSize) && newVal !== oldVal && newVal.pageSize !== oldVal.pageSize) {
$scope.pagingOptions.currentPage = 1;
$scope.loadTable();
}
}, true);
function getBrokerMBean(jolokia) {
var mbean = null;
var selection = workspace.selection;
var folderNames = selection.folderNames;
mbean = "" + folderNames[0] + ":broker=" + folderNames[1];
ARTEMIS.log.info("broker=" + mbean);
return mbean;
};
$scope.refresh();
};
return ARTEMIS;
} (ARTEMIS || {}));

View File

@ -1,76 +0,0 @@
/*
* 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.
*/
/// <reference path="artemisPlugin.ts"/>
var ARTEMIS;
(function (ARTEMIS) {
ARTEMIS.module.controller("ARTEMIS.TreeHeaderController", ["$scope", function ($scope) {
$scope.expandAll = function () {
Tree.expandAll("#artemistree");
};
$scope.contractAll = function () {
Tree.contractAll("#artemistree");
};
}]);
ARTEMIS.module.controller("ARTEMIS.TreeController", ["$scope", "$location", "workspace", "localStorage", function ($scope, $location, workspace, localStorage) {
var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis";
ARTEMIS.log.info("init tree " + artemisJmxDomain);
$scope.$on("$routeChangeSuccess", function (event, current, previous) {
// lets do this asynchronously to avoid Error: $digest already in progress
setTimeout(updateSelectionFromURL, 50);
});
$scope.$watch('workspace.tree', function () {
reloadTree();
});
$scope.$on('jmxTreeUpdated', function () {
reloadTree();
});
function reloadTree() {
ARTEMIS.log.info("workspace tree has changed, lets reload the artemis tree");
var children = [];
var tree = workspace.tree;
ARTEMIS.log.info("tree="+tree);
if (tree) {
var domainName = artemisJmxDomain;
var folder = tree.get(domainName);
ARTEMIS.log.info("folder="+folder);
if (folder) {
children = folder.children;
}
var treeElement = $("#artemistree");
Jmx.enableTree($scope, $location, workspace, treeElement, children, true);
// lets do this asynchronously to avoid Error: $digest already in progress
setTimeout(updateSelectionFromURL, 50);
}
}
function updateSelectionFromURL() {
Jmx.updateTreeSelectionFromURLAndAutoSelect($location, $("#artemistree"), function (first) {
// use function to auto select the queue folder on the 1st broker
var jms = first.getChildren()[0];
ARTEMIS.log.info("%%%%%%" + jms);
var queues = jms.getChildren()[0];
if (queues && queues.data.title === 'Queue') {
first = queues;
first.expand(true);
return first;
}
return null;
}, true);
}
}]);
})(ARTEMIS || (ARTEMIS = {}));

View File

@ -1,92 +0,0 @@
/*
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.
Architecture
*/
function ArtemisConsole() {
this.getServerAttributes = function (jolokia, mBean) {
var req1 = { type: "read", mbean: mBean};
return jolokia.request(req1, {method: "post"});
};
this.createAddress = function (mbean, jolokia, name, routingType, method) {
jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, routingType, method);
};
this.deleteAddress = function (mbean, jolokia, name, method) {
jolokia.execute(mbean, "deleteAddress(java.lang.String)", name, method);
};
this.createQueue = function (mbean, jolokia, address, routingType, name, durable, filter, maxConsumers, purgeWhenNoConsumers, method) {
jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, routingType, name, filter, durable, maxConsumers, purgeWhenNoConsumers, true, method);
};
this.deleteQueue = function (mbean, jolokia, name, method) {
jolokia.execute(mbean, "destroyQueue(java.lang.String)", name, method);
};
this.purgeQueue = function (mbean, jolokia, method) {
jolokia.execute(mbean, "removeAllMessages()", method);
};
this.browse = function (mbean, jolokia, method) {
jolokia.request({ type: 'exec', mbean: mbean, operation: 'browse()' }, method);
};
this.deleteMessage = function (mbean, jolokia, id, method) {
ARTEMIS.log.info("executing on " + mbean);
jolokia.execute(mbean, "removeMessage(long)", id, method);
};
this.moveMessage = function (mbean, jolokia, id, queueName, method) {
jolokia.execute(mbean, "moveMessage(long,java.lang.String)", id, queueName, method);
};
this.retryMessage = function (mbean, jolokia, id, method) {
jolokia.execute(mbean, "retryMessage(long)", id, method);
};
this.sendMessage = function (mbean, jolokia, headers, type, body, durable, user, pwd, method) {
jolokia.execute(mbean, "sendMessage(java.util.Map, int, java.lang.String, boolean, java.lang.String, java.lang.String)", headers, type, body, durable, user, pwd, method);
};
this.getConsumers = function (mbean, jolokia, method) {
jolokia.request({ type: 'exec', mbean: mbean, operation: 'listAllConsumersAsJSON()' }, method);
};
this.getRemoteBrokers = function (mbean, jolokia, method) {
jolokia.request({ type: 'exec', mbean: mbean, operation: 'listNetworkTopology()' }, method);
};
this.ownUnescape = function (name) {
//simple return unescape(name); does not work for this :(
return name.replace(/\\\\/g, "\\").replace(/\\\*/g, "*").replace(/\\\?/g, "?");
};
this.isBackup = function (jolokia, mBean) {
var req1 = { type: "read", mbean: mBean, attribute: "Backup"};
return jolokia.request(req1, {method: "get"});
};
}
function getServerAttributes() {
var console = new ArtemisConsole();
return console.getVersion(new Jolokia("http://localhost:8161/jolokia/"));
}

View File

@ -35,7 +35,7 @@
<activemq.basedir>${project.basedir}/..</activemq.basedir>
<hawtio.version>1.5.12</hawtio.version>
<hawtio.version>2.11.0</hawtio.version>
<jline.version>3.2.0</jline.version>
<junit-version>4.11</junit-version>
<log4j-version>1.2.17</log4j-version>

View File

@ -91,7 +91,7 @@ public class ActiveMQMessage implements javax.jms.Message {
entry.getKey().equals("priority")) {
// Ignore
} else if (entry.getKey().equals("userID")) {
jmsMessage.put("JMSMessageID", entry.getValue().toString());
jmsMessage.put(" JMSMessageID", entry.getValue().toString());
} else {
Object value = entry.getValue();
if (value instanceof SimpleString) {

View File

@ -24,6 +24,7 @@ import java.util.Map;
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.core.config.impl.Validators;
import org.apache.activemq.artemis.core.deployers.Deployable;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
import org.apache.activemq.artemis.jms.server.ActiveMQJMSServerLogger;
@ -76,7 +77,7 @@ public class FileJMSConfiguration extends JMSConfigurationImpl implements Deploy
public void buildService(ActiveMQSecurityManager securityManager,
MBeanServer mBeanServer,
Map<String, Deployable> deployables,
Map<String, ActiveMQComponent> components) throws Exception {
Map<String, ActiveMQComponent> components, ActivateCallback activateCallback) throws Exception {
ActiveMQServerImpl server = (ActiveMQServerImpl) components.get("core");
components.put(CONFIGURATION_SCHEMA_ROOT_ELEMENT, new JMSServerManagerImpl(server, this));
}

View File

@ -91,7 +91,7 @@ public class OsgiBroker {
FileDeploymentManager fileDeploymentManager = new FileDeploymentManager(configurationUrl);
fileDeploymentManager.addDeployable(configuration).addDeployable(jmsConfiguration).readConfiguration();
components = fileDeploymentManager.buildService(security, ManagementFactory.getPlatformMBeanServer());
components = fileDeploymentManager.buildService(security, ManagementFactory.getPlatformMBeanServer(), null);
final ActiveMQServer server = (ActiveMQServer) components.get("core");

View File

@ -23,6 +23,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.activemq.artemis.core.deployers.Deployable;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
import org.apache.activemq.artemis.utils.XMLUtil;
@ -86,12 +87,12 @@ public class FileDeploymentManager {
* Build a set of ActiveMQComponents from the Deployables configured
*/
public Map<String, ActiveMQComponent> buildService(ActiveMQSecurityManager securityManager,
MBeanServer mBeanServer) throws Exception {
MBeanServer mBeanServer, ActivateCallback activateCallback) throws Exception {
Map<String, ActiveMQComponent> components = new HashMap<>();
for (Deployable deployable : deployables.values()) {
// if the deployable was parsed then build the service
if (deployable.isParsed()) {
deployable.buildService(securityManager, mBeanServer, deployables, components);
deployable.buildService(securityManager, mBeanServer, deployables, components, activateCallback);
}
}
return components;

View File

@ -21,12 +21,22 @@ import java.io.Serializable;
public interface HAPolicyConfiguration extends Serializable {
enum TYPE {
LIVE_ONLY,
REPLICATED,
REPLICA,
SHARED_STORE_MASTER,
SHARED_STORE_SLAVE,
COLOCATED
LIVE_ONLY("Live Only"),
REPLICATED("Replicated"),
REPLICA("Replica"),
SHARED_STORE_MASTER("Shared Store Master"),
SHARED_STORE_SLAVE("Shared Store Slave"),
COLOCATED("Colocated");
private String name;
TYPE(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
TYPE getType();

View File

@ -22,6 +22,7 @@ import java.util.Map;
import org.apache.activemq.artemis.core.deployers.Deployable;
import org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
@ -75,8 +76,12 @@ public final class FileConfiguration extends ConfigurationImpl implements Deploy
public void buildService(ActiveMQSecurityManager securityManager,
MBeanServer mBeanServer,
Map<String, Deployable> deployables,
Map<String, ActiveMQComponent> components) {
components.put(getRootElement(), new ActiveMQServerImpl(this, mBeanServer, securityManager));
Map<String, ActiveMQComponent> components, ActivateCallback activateCallback) {
ActiveMQServerImpl activeMQServer = new ActiveMQServerImpl(this, mBeanServer, securityManager);
if (activateCallback != null) {
activeMQServer.registerActivateCallback(activateCallback);
}
components.put(getRootElement(), activeMQServer);
}
@Override

View File

@ -26,6 +26,7 @@ import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.CoreAddressConfiguration;
import org.apache.activemq.artemis.core.deployers.Deployable;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
import org.apache.activemq.artemis.utils.XMLConfigurationUtil;
@ -90,7 +91,7 @@ public class LegacyJMSConfiguration implements Deployable {
public void buildService(ActiveMQSecurityManager securityManager,
MBeanServer mBeanServer,
Map<String, Deployable> deployables,
Map<String, ActiveMQComponent> components) throws Exception {
Map<String, ActiveMQComponent> components, ActivateCallback activateCallback) throws Exception {
}
@Override

View File

@ -20,6 +20,7 @@ import javax.management.MBeanServer;
import java.net.URL;
import java.util.Map;
import org.apache.activemq.artemis.core.server.ActivateCallback;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
import org.w3c.dom.Element;
@ -56,6 +57,6 @@ public interface Deployable {
void buildService(ActiveMQSecurityManager securityManager,
MBeanServer mBeanServer,
Map<String, Deployable> deployables,
Map<String, ActiveMQComponent> components) throws Exception;
Map<String, ActiveMQComponent> components, ActivateCallback activateCallback) throws Exception;
}

View File

@ -740,7 +740,7 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
}
@Override
public int getAddressMemoryUsagePercentage() {
public int getAddressMemoryUsagePercentage() {
if (AuditLogger.isEnabled()) {
AuditLogger.getAddressMemoryUsagePercentage(this.server);
}
@ -758,6 +758,11 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
return (int) result;
}
@Override
public String getHAPolicy() {
return configuration.getHAPolicyConfiguration().getType().getName();
}
@Override
public long getAuthenticationCacheSize() {
if (AuditLogger.isEnabled()) {

View File

@ -1479,10 +1479,14 @@ public class QueueControlImpl extends AbstractControl implements QueueControl {
@Override
public CompositeData[] browse(int page, int pageSize) throws Exception {
return browse(page, pageSize, null);
}
@Override
public CompositeData[] browse(int page, int pageSize, String filter) throws Exception {
if (AuditLogger.isEnabled()) {
AuditLogger.browse(queue, page, pageSize);
}
String filter = null;
checkStarted();
clearIO();

View File

@ -1710,6 +1710,16 @@ public interface ActiveMQServerLogger extends BasicLogger {
@Message(id = 222295, value = "Subscription {0} uses wildcard address {1} but no matching address-setting has configured the shared page-store-name; counters may be inaccurate", format = Message.Format.MESSAGE_FORMAT)
void wildcardRoutingWithoutSharedPageStore(SimpleString queueName, SimpleString address);
@LogMessage(level = Logger.Level.WARN)
@Message(id = 222296, value = "Unable to deploy Hawtio MBeam, console client side RBAC not available",
format = Message.Format.MESSAGE_FORMAT)
void unableToDeployHawtioMBean(@Cause Exception e);
@LogMessage(level = Logger.Level.WARN)
@Message(id = 222297, value = "Unable to start Management Context, RBAC not available",
format = Message.Format.MESSAGE_FORMAT)
void unableStartManagementContext(@Cause Exception e);
@LogMessage(level = Logger.Level.ERROR)
@Message(id = 224000, value = "Failure in initialisation", format = Message.Format.MESSAGE_FORMAT)
void initializationError(@Cause Throwable e);

View File

@ -17,6 +17,7 @@
package org.apache.activemq.artemis.core.server.management;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.logs.AuditLogger;
import javax.management.Attribute;
@ -25,6 +26,7 @@ import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.security.auth.Subject;
import java.io.IOException;
@ -61,7 +63,7 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
} else if ("setAttributes".equals(method.getName())) {
handleSetAttributes((MBeanServer) proxy, objectName, (AttributeList) args[1]);
} else if ("invoke".equals(method.getName())) {
handleInvoke(objectName, (String) args[1], (Object[]) args[2], (String[]) args[3]);
handleInvoke(objectName, (String) args[1]);
}
return null;
@ -78,7 +80,7 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
if (prefix == null) {
//ActiveMQServerLogger.LOGGER.debug("Attribute " + attributeName + " can not be found for MBean " + objectName.toString());
} else {
handleInvoke(objectName, prefix + attributeName, new Object[]{}, new String[]{});
handleInvoke(objectName, prefix + attributeName);
}
}
@ -101,7 +103,7 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
if (dataType == null)
throw new IllegalStateException("Attribute data type can not be found");
handleInvoke(objectName, "set" + attribute.getName(), new Object[]{attribute.getValue()}, new String[]{dataType});
handleInvoke(objectName, "set" + attribute.getName());
}
private void handleSetAttributes(MBeanServer proxy, ObjectName objectName, AttributeList attributes) throws JMException, IOException {
@ -114,11 +116,32 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
return jmxAccessControlList.isInWhiteList(objectName);
}
void handleInvoke(ObjectName objectName, String operationName, Object[] params, String[] signature) throws IOException {
public boolean canInvoke(String object, String operationName) {
ObjectName objectName = null;
try {
objectName = ObjectName.getInstance(object);
} catch (MalformedObjectNameException e) {
ActiveMQServerLogger.LOGGER.debug("can't check invoke rights as object name invalid: " + objectName);
return false;
}
if (canBypassRBAC(objectName)) {
return true;
}
List<String> requiredRoles = getRequiredRoles(objectName, operationName);
for (String role : requiredRoles) {
if (currentUserHasRole(role)) {
return true;
}
}
ActiveMQServerLogger.LOGGER.info(object + " " + operationName + " " + false);
return false;
}
void handleInvoke(ObjectName objectName, String operationName) throws IOException {
if (canBypassRBAC(objectName)) {
return;
}
List<String> requiredRoles = getRequiredRoles(objectName, operationName, params, signature);
List<String> requiredRoles = getRequiredRoles(objectName, operationName);
for (String role : requiredRoles) {
if (currentUserHasRole(role))
return;
@ -129,7 +152,7 @@ public class ArtemisMBeanServerGuard implements InvocationHandler {
throw new SecurityException("Insufficient roles/credentials for operation");
}
List<String> getRequiredRoles(ObjectName objectName, String methodName, Object[] params, String[] signature) throws IOException {
List<String> getRequiredRoles(ObjectName objectName, String methodName) {
return jmxAccessControlList.getRolesForObject(objectName, methodName);
}

View File

@ -0,0 +1,39 @@
/*
* 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.activemq.artemis.core.server.management;
import org.apache.activemq.artemis.api.core.management.Operation;
import javax.management.MBeanOperationInfo;
import javax.management.openmbean.TabularData;
import java.util.List;
import java.util.Map;
public interface HawtioSecurityControl {
@Operation(desc = "Can invoke an Object", impact = MBeanOperationInfo.ACTION)
boolean canInvoke(String objectName) throws Exception;
@Operation(desc = "Can invoke an Object", impact = MBeanOperationInfo.ACTION)
boolean canInvoke(String objectName, String methodName) throws Exception;
@Operation(desc = "Can invoke an Object", impact = MBeanOperationInfo.ACTION)
boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception;
@Operation(desc = "Can invoke a number of Objects", impact = MBeanOperationInfo.ACTION)
TabularData canInvoke(Map<String, List<String>> bulkQuery) throws Exception;
}

View File

@ -20,20 +20,25 @@ package org.apache.activemq.artemis.core.server.management;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.activemq.artemis.core.config.JMXConnectorConfiguration;
import org.apache.activemq.artemis.core.persistence.StorageManager;
import org.apache.activemq.artemis.core.server.ServiceComponent;
import org.apache.activemq.artemis.core.server.management.impl.HawtioSecurityControlImpl;
import javax.management.NotCompliantMBeanException;
public class ManagementContext implements ServiceComponent {
private AtomicBoolean isStarted = new AtomicBoolean(false);
private JMXAccessControlList accessControlList;
private JMXConnectorConfiguration jmxConnectorConfiguration;
private ManagementConnector mBeanServer;
private ArtemisMBeanServerGuard guardHandler;
@Override
public void start() throws Exception {
if (accessControlList != null) {
//if we are configured then assume we want to use the guard so set the system property
System.setProperty("javax.management.builder.initial", ArtemisMBeanServerBuilder.class.getCanonicalName());
ArtemisMBeanServerGuard guardHandler = new ArtemisMBeanServerGuard();
guardHandler = new ArtemisMBeanServerGuard();
guardHandler.setJMXAccessControlList(accessControlList);
ArtemisMBeanServerBuilder.setGuard(guardHandler);
}
@ -81,4 +86,17 @@ public class ManagementContext implements ServiceComponent {
public JMXConnectorConfiguration getJmxConnectorConfiguration() {
return jmxConnectorConfiguration;
}
public HawtioSecurityControl getSecurityMBean(StorageManager storageManager) {
try {
return new HawtioSecurityControlImpl(guardHandler, storageManager);
} catch (NotCompliantMBeanException e) {
e.printStackTrace();
return null;
}
}
public ArtemisMBeanServerGuard getArtemisMBeanServerGuard() {
return guardHandler;
}
}

View File

@ -132,4 +132,8 @@ public interface ManagementService extends NotificationService, ActiveMQComponen
Object[] getResources(Class<?> resourceType);
ICoreMessage handleMessage(Message message) throws Exception;
void registerHawtioSecurity(ArtemisMBeanServerGuard securityMBean) throws Exception;
void unregisterHawtioSecurity() throws Exception;
}

View File

@ -0,0 +1,155 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.core.server.management.impl;
import org.apache.activemq.artemis.core.management.impl.AbstractControl;
import org.apache.activemq.artemis.core.management.impl.MBeanInfoHelper;
import org.apache.activemq.artemis.core.persistence.StorageManager;
import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard;
import org.apache.activemq.artemis.core.server.management.HawtioSecurityControl;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import java.util.List;
import java.util.Map;
public class HawtioSecurityControlImpl extends AbstractControl implements HawtioSecurityControl {
/**
* The Tabular Type returned by the {@link #canInvoke(Map)} operation. The rows consist of
* {@link #CAN_INVOKE_RESULT_ROW_TYPE} entries.
* It has a composite key with consists of the "ObjectName" and "Method" columns.
*/
static final TabularType CAN_INVOKE_TABULAR_TYPE = SecurityMBeanOpenTypeInitializer.TABULAR_TYPE;
/**
* A row as returned by the {@link #CAN_INVOKE_TABULAR_TYPE}. The columns of the row are defined
* by {@link #CAN_INVOKE_RESULT_COLUMNS}.
*/
static final CompositeType CAN_INVOKE_RESULT_ROW_TYPE = SecurityMBeanOpenTypeInitializer.ROW_TYPE;
/**
* The columns contained in a {@link #CAN_INVOKE_RESULT_ROW_TYPE}. The data types for these columns are
* as follows:
* <ul>
* <li>"ObjectName" : {@link SimpleType#STRING}</li>
* <li>"Method" : {@link SimpleType#STRING}</li>
* <li>"CanInvoke" : {@link SimpleType#BOOLEAN}</li>
* </ul>
*/
static final String[] CAN_INVOKE_RESULT_COLUMNS = SecurityMBeanOpenTypeInitializer.COLUMNS;
private final ArtemisMBeanServerGuard mBeanServerGuard;
public HawtioSecurityControlImpl(ArtemisMBeanServerGuard mBeanServerGuard, StorageManager storageManager) throws NotCompliantMBeanException {
super(HawtioSecurityControl.class, storageManager);
this.mBeanServerGuard = mBeanServerGuard;
}
@Override
protected MBeanOperationInfo[] fillMBeanOperationInfo() {
return MBeanInfoHelper.getMBeanOperationsInfo(HawtioSecurityControl.class);
}
@Override
protected MBeanAttributeInfo[] fillMBeanAttributeInfo() {
return MBeanInfoHelper.getMBeanAttributesInfo(HawtioSecurityControl.class);
}
@Override
public boolean canInvoke(String objectName) throws Exception {
return mBeanServerGuard == null || mBeanServerGuard.canInvoke(objectName, null);
}
@Override
public boolean canInvoke(String objectName, String methodName) throws Exception {
return mBeanServerGuard == null || mBeanServerGuard.canInvoke(objectName, methodName);
}
@Override
public boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception {
return mBeanServerGuard == null || mBeanServerGuard.canInvoke(objectName, methodName);
}
@Override
public TabularData canInvoke(Map<String, List<String>> bulkQuery) throws Exception {
TabularData table = new TabularDataSupport(CAN_INVOKE_TABULAR_TYPE);
for (Map.Entry<String, List<String>> entry : bulkQuery.entrySet()) {
String objectName = entry.getKey();
List<String> methods = entry.getValue();
if (methods.size() == 0) {
boolean res = canInvoke(objectName);
CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
CAN_INVOKE_RESULT_COLUMNS,
new Object[]{objectName, "", true});
table.put(data);
} else {
for (String method : methods) {
CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
CAN_INVOKE_RESULT_COLUMNS,
new Object[]{objectName, method, true});
table.put(data);
}
}
}
return table;
}
// A member class is used to initialize final fields, as this needs to do some exception handling...
static class SecurityMBeanOpenTypeInitializer {
private static final String[] COLUMNS = new String[]{"ObjectName", "Method", "CanInvoke"};
private static final CompositeType ROW_TYPE;
static {
try {
ROW_TYPE = new CompositeType("CanInvokeRowType",
"The rows of a CanInvokeTabularType table.",
COLUMNS,
new String[]{
"The ObjectName of the MBean checked",
"The Method to checked. This can either be a bare method name which means 'any method with this name' " +
"or a specific overload such as foo(java.lang.String). If an empty String is returned this means 'any' method.",
"true if the method or mbean can potentially be invoked by the current user."},
new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.BOOLEAN}
);
} catch (OpenDataException e) {
throw new RuntimeException(e);
}
}
private static final TabularType TABULAR_TYPE;
static {
try {
TABULAR_TYPE = new TabularType("CanInvokeTabularType", "Result of canInvoke() bulk operation", ROW_TYPE,
new String[]{"ObjectName", "Method"});
} catch (OpenDataException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -93,6 +93,8 @@ import org.apache.activemq.artemis.core.server.cluster.BroadcastGroup;
import org.apache.activemq.artemis.core.server.cluster.ClusterConnection;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.apache.activemq.artemis.core.server.impl.CleaningActivateCallback;
import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard;
import org.apache.activemq.artemis.core.server.management.HawtioSecurityControl;
import org.apache.activemq.artemis.core.server.management.ManagementService;
import org.apache.activemq.artemis.core.server.management.Notification;
import org.apache.activemq.artemis.core.server.management.NotificationListener;
@ -487,6 +489,21 @@ public class ManagementServiceImpl implements ManagementService {
unregisterFromRegistry(ResourceNames.CORE_CLUSTER_CONNECTION + name);
}
@Override
public void registerHawtioSecurity(ArtemisMBeanServerGuard mBeanServerGuard) throws Exception {
ObjectName objectName = objectNameBuilder.getManagementContextObjectName();
HawtioSecurityControl control = new HawtioSecurityControlImpl(mBeanServerGuard, storageManager);
registerInJMX(objectName, control);
registerInRegistry(ResourceNames.MANAGEMENT_SECURITY, control);
}
@Override
public void unregisterHawtioSecurity() throws Exception {
ObjectName objectName = objectNameBuilder.getManagementContextObjectName();
unregisterFromJMX(objectName);
unregisterFromRegistry(ResourceNames.MANAGEMENT_SECURITY);
}
@Override
public ICoreMessage handleMessage(Message message) throws Exception {
message = message.toCore();

View File

@ -87,7 +87,7 @@ public class FileConfigurationParserTest extends ActiveMQTestBase {
FileDeploymentManager deploymentManager = new FileDeploymentManager(filename);
deploymentManager.addDeployable(fc);
deploymentManager.readConfiguration();
ActiveMQServer server = addServer((ActiveMQServer) deploymentManager.buildService(null, null).get("core"));
ActiveMQServer server = addServer((ActiveMQServer) deploymentManager.buildService(null, null, null).get("core"));
server.start();
assertEquals(0, server.locateQueue(SimpleString.toSimpleString("q")).getMaxConsumers());
}

View File

@ -50,6 +50,7 @@ import org.apache.activemq.artemis.core.server.cluster.Bridge;
import org.apache.activemq.artemis.core.server.cluster.BroadcastGroup;
import org.apache.activemq.artemis.core.server.cluster.ClusterConnection;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.apache.activemq.artemis.core.server.management.ArtemisMBeanServerGuard;
import org.apache.activemq.artemis.core.server.management.ManagementService;
import org.apache.activemq.artemis.core.server.management.Notification;
import org.apache.activemq.artemis.core.server.management.NotificationListener;
@ -339,6 +340,16 @@ public class ClusteredResetMockTest extends ActiveMQTestBase {
return null;
}
@Override
public void registerHawtioSecurity(ArtemisMBeanServerGuard securityMBean) throws Exception {
}
@Override
public void unregisterHawtioSecurity() throws Exception {
}
@Override
public void start() throws Exception {

View File

@ -93,7 +93,7 @@
<fuse.mqtt.client.version>1.16</fuse.mqtt.client.version>
<guava.version>24.1.1-jre</guava.version>
<jboss.logging.version>3.4.0.Final</jboss.logging.version>
<jetty.version>9.4.26.v20200117</jetty.version>
<jetty.version>9.4.27.v20200227</jetty.version>
<jgroups.version>3.6.13.Final</jgroups.version>
<maven.assembly.plugin.version>2.4</maven.assembly.plugin.version>
<mockito.version>3.3.3</mockito.version>
@ -1686,6 +1686,7 @@
<reportFile>${activemq.basedir}/ratReport.txt</reportFile>
<skip>${skipLicenseCheck}</skip>
<excludes>
<exclude>**/src/main/webapp/hawtconfig.json</exclude>
<exclude>.repository/**</exclude>
<exclude>.travis.yml</exclude>
<exclude>.github/workflows/*</exclude>

Some files were not shown because too many files have changed in this diff Show More