This is an automated email from the ASF dual-hosted git repository. orudyy pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git
The following commit(s) were added to refs/heads/master by this push: new a33aca4 QPID-8360: [Broker-J]Add broker and virtual host loggers storing log records in database a33aca4 is described below commit a33aca40bd224453ad8b0939b2f5af385017b946 Author: Alex Rudyy <oru...@apache.org> AuthorDate: Fri Sep 6 15:04:53 2019 +0100 QPID-8360: [Broker-J]Add broker and virtual host loggers storing log records in database --- broker-plugins/jdbc-logging-logback/pom.xml | 95 ++++++++++++ .../logging/logback/jdbc/JDBCBrokerLogger.java | 56 +++++++ .../logging/logback/jdbc/JDBCBrokerLoggerImpl.java | 172 +++++++++++++++++++++ .../logging/logback/jdbc/JDBCLoggerHelper.java | 114 ++++++++++++++ .../logback/jdbc/JDBCSettingsDBNameResolver.java | 49 ++++++ .../jdbc/JDBCSettingsDrivenConnectionSource.java | 110 +++++++++++++ .../logback/jdbc/JDBCVirtualHostLogger.java} | 22 ++- .../logback/jdbc/JDBCVirtualHostLoggerImpl.java | 138 +++++++++++++++++ .../management/logger/brokerlogger/jdbc/add.js | 41 +++++ .../management/logger/brokerlogger/jdbc/show.js | 56 +++++++ .../logger/virtualhostlogger/jdbc/add.js | 39 +++++ .../logger/virtualhostlogger/jdbc/show.js | 57 +++++++ .../src/main/java/resources/logger/jdbc/add.html | 93 +++++++++++ .../src/main/java/resources/logger/jdbc/show.html | 38 +++++ .../logback/jdbc/InMemoryDatabaseTestBase.java | 65 ++++++++ .../logback/jdbc/JDBCBrokerLoggerImplTest.java | 150 ++++++++++++++++++ .../logging/logback/jdbc/JDBCLoggerHelperTest.java | 114 ++++++++++++++ .../jdbc/JDBCSettingsDBNameResolverTest.java | 60 +++++++ .../JDBCSettingsDrivenConnectionSourceTest.java | 104 +++++++++++++ .../jdbc/JDBCVirtualHostLoggerImplTest.java | 138 +++++++++++++++++ .../js/qpid/management/store/pool/bonecp/show.js | 5 +- .../qpid/server/store/jdbc/JDBCSettings.java | 6 + .../apache/qpid/server/store/jdbc/JdbcUtils.java | 36 +++-- .../qpid/management/store/pool/ConnectionPool.js | 113 ++++++++++++++ .../server/logging/logback/AbstractLogger.java | 7 +- .../logging/logback/BrokerFileLoggerImpl.java | 48 +----- .../logback/BrokerLoggerStatusListener.java | 83 ++++++++++ ...st.java => BrokerLoggerStatusListenerTest.java} | 16 +- .../src/main/java/resources/addLogger.html | 5 + .../java/resources/js/qpid/management/addLogger.js | 27 +++- broker/pom.xml | 6 + pom.xml | 8 + 32 files changed, 1996 insertions(+), 75 deletions(-) diff --git a/broker-plugins/jdbc-logging-logback/pom.xml b/broker-plugins/jdbc-logging-logback/pom.xml new file mode 100644 index 0000000..5c36aa5 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/pom.xml @@ -0,0 +1,95 @@ +<?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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-parent</artifactId> + <version>8.0.0-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + + <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId> + <name>Apache Qpid Broker-J LogBack JDBC Logging Plug-in</name> + <description>LogBack JDBC Logging broker plug-in</description> + + <dependencies> + + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-plugins-logging-logback</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-plugins-jdbc-store</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-codegen</artifactId> + <optional>true</optional> + </dependency> + + <!-- test dependencies --> + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-test-utils</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.derby</groupId> + <artifactId>derby</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-core</artifactId> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>${h2.version}</version> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <resources> + <resource> + <directory>src/main/resources</directory> + </resource> + <resource> + <directory>src/main/java</directory> + <includes> + <include>resources/</include> + </includes> + </resource> + </resources> + </build> + +</project> diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java new file mode 100644 index 0000000..244b103 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLogger.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import org.apache.qpid.server.model.BrokerLogger; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedContextDefault; +import org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +public interface JDBCBrokerLogger<X extends JDBCBrokerLogger<X>> extends BrokerLogger<X>, JDBCSettings +{ + String BROKER_FAIL_ON_JDBC_LOGGER_ERROR = "qpid.broker.failOnJdbcLoggerError"; + @ManagedContextDefault(name = BROKER_FAIL_ON_JDBC_LOGGER_ERROR) + @SuppressWarnings("unused") + String DEFAULT_BROKER_FAIL_ON_JDBC_LOGGER_ERROR = "false"; + + @Override + @ManagedAttribute(mandatory=true) + String getConnectionUrl(); + + @Override + @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE, + validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} ) + String getConnectionPoolType(); + + @Override + @ManagedAttribute + String getUsername(); + + @Override + @ManagedAttribute(secure=true) + String getPassword(); + + @Override + @ManagedAttribute + String getTableNamePrefix(); + +} diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java new file mode 100644 index 0000000..c371184 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImpl.java @@ -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. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import java.sql.SQLException; +import java.util.Map; +import java.util.Set; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.Context; +import ch.qos.logback.core.status.StatusManager; +import com.google.common.util.concurrent.ListenableFuture; + +import org.apache.qpid.server.logging.logback.AbstractBrokerLogger; +import org.apache.qpid.server.logging.logback.BrokerLoggerStatusListener; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.SystemConfig; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +@SuppressWarnings("unused") +@ManagedObject(category = false, type = JDBCBrokerLoggerImpl.CONFIGURED_OBJECT_TYPE, + validChildTypes = "org.apache.qpid.server.logging.logback.AbstractLogger#getSupportedBrokerLoggerChildTypes()") +public class JDBCBrokerLoggerImpl extends AbstractBrokerLogger<JDBCBrokerLoggerImpl> + implements JDBCBrokerLogger<JDBCBrokerLoggerImpl> +{ + static final String CONFIGURED_OBJECT_TYPE = "Jdbc"; + private final JDBCLoggerHelper _jdbcLoggerHelper; + + private volatile BrokerLoggerStatusListener _logbackStatusListener; + private volatile StatusManager _statusManager; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _connectionUrl; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _connectionPoolType; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _username; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _password; + + @ManagedAttributeField(afterSet = "restartAppenderIfExists") + private String _tableNamePrefix; + + @ManagedObjectFactoryConstructor + protected JDBCBrokerLoggerImpl(final Map<String, Object> attributes, Broker<?> broker) + { + super(attributes, broker); + _jdbcLoggerHelper = new JDBCLoggerHelper(); + } + + @Override + public String getConnectionUrl() + { + return _connectionUrl; + } + + @Override + public String getConnectionPoolType() + { + return _connectionPoolType; + } + + @Override + public String getUsername() + { + return _username; + } + + @Override + public String getPassword() + { + return _password; + } + + @Override + public String getTableNamePrefix() + { + return _tableNamePrefix; + } + + @Override + protected ListenableFuture<Void> onClose() + { + onCloseOrDelete(); + return super.onClose(); + } + + @Override + protected ListenableFuture<Void> onDelete() + { + onCloseOrDelete(); + return super.onDelete(); + } + + @Override + protected void validateChange(ConfiguredObject<?> proxyForValidation, Set<String> changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + if (changedAttributes.contains(JDBCSettings.CONNECTION_URL) + || changedAttributes.contains(JDBCSettings.USERNAME) + || changedAttributes.contains(JDBCSettings.PASSWORD) + || changedAttributes.contains(JDBCSettings.CONNECTION_POOL_TYPE)) + { + _jdbcLoggerHelper.validateConnectionSourceSettings(this, (JDBCBrokerLogger) proxyForValidation); + } + } + + @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + _jdbcLoggerHelper.validateConnectionSourceSettings(this, this); + } + + @Override + protected Appender<ILoggingEvent> createAppenderInstance(final Context context) + { + final SystemConfig<?> systemConfig = getAncestor(SystemConfig.class); + _logbackStatusListener = new BrokerLoggerStatusListener(this, + systemConfig, + BROKER_FAIL_ON_JDBC_LOGGER_ERROR, + SQLException.class); + _statusManager = context.getStatusManager(); + _statusManager.add(_logbackStatusListener); + + return _jdbcLoggerHelper.createAppenderInstance(context, this, this); + } + + private void onCloseOrDelete() + { + if (_statusManager != null) + { + _statusManager.remove(_logbackStatusListener); + } + } + + private void restartAppenderIfExists() + { + _jdbcLoggerHelper.restartAppenderIfExists(getAppender()); + } + + private void restartConnectionSourceIfExists() + { + _jdbcLoggerHelper.restartConnectionSourceIfExists(getAppender()); + } + +} diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java new file mode 100644 index 0000000..d6edd2b --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelper.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import ch.qos.logback.classic.db.DBAppender; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.Context; +import ch.qos.logback.core.db.ConnectionSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +class JDBCLoggerHelper +{ + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCLoggerHelper.class); + final static ch.qos.logback.classic.Logger ROOT_LOGGER = + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)); + + Appender<ILoggingEvent> createAppenderInstance(final Context context, + final ConfiguredObject<?> logger, + final JDBCSettings settings) + { + try + { + final JDBCSettingsDBNameResolver dbNameResolver = new JDBCSettingsDBNameResolver(settings); + final ConnectionSource connectionSource = createConnectionSource(context, logger, settings); + final DBAppender appender = new DBAppender(); + appender.setDbNameResolver(dbNameResolver); + appender.setConnectionSource(connectionSource); + appender.setContext(context); + appender.start(); + return appender; + } + catch (Exception e) + { + LOGGER.error("Failed to create appender", e); + throw new IllegalConfigurationException("Cannot create appender"); + } + } + + void restartAppenderIfExists(final Appender appender) + { + if (appender != null) + { + appender.stop(); + appender.start(); + } + } + + void restartConnectionSourceIfExists(final Appender appender) + { + if (appender instanceof DBAppender) + { + final ConnectionSource connectionSource = ((DBAppender) appender).getConnectionSource(); + if (connectionSource != null) + { + connectionSource.stop(); + connectionSource.start(); + } + } + } + + void validateConnectionSourceSettings(final ConfiguredObject<?> logger, final JDBCSettings settings) + { + try + { + final ConnectionSource connectionSource = createConnectionSource(logger, settings); + connectionSource.getConnection().close(); + } + catch (Exception e) + { + throw new IllegalConfigurationException( + "Cannot create connection source from given URL, credentials and connection pool type"); + } + } + + private ConnectionSource createConnectionSource(final ConfiguredObject<?> logger, + final JDBCSettings settings) + { + return createConnectionSource(ROOT_LOGGER.getLoggerContext(), logger, settings); + } + + private ConnectionSource createConnectionSource(final Context context, + final ConfiguredObject<?> logger, + final JDBCSettings settings) + { + final JDBCSettingsDrivenConnectionSource connectionSource = + new JDBCSettingsDrivenConnectionSource(logger, settings); + connectionSource.setContext(context); + connectionSource.start(); + return connectionSource; + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java new file mode 100644 index 0000000..cc28635 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolver.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import ch.qos.logback.classic.db.names.DBNameResolver; + +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +class JDBCSettingsDBNameResolver implements DBNameResolver +{ + private JDBCSettings _settings; + + JDBCSettingsDBNameResolver(final JDBCSettings settings) + { + _settings = settings; + } + + @Override + public <N extends Enum<?>> String getTableName(final N tableName) + { + String settingsTableNamePrefix = _settings.getTableNamePrefix() ; + final String prefix = settingsTableNamePrefix == null ? "" : settingsTableNamePrefix; + final String name = prefix + tableName.toString(); + return name.toLowerCase(); + } + + @Override + public <N extends Enum<?>> String getColumnName(final N columnName) + { + return columnName.toString().toLowerCase(); + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java new file mode 100644 index 0000000..d2f76f6 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSource.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.concurrent.atomic.AtomicReference; + +import ch.qos.logback.core.db.ConnectionSourceBase; +import ch.qos.logback.core.db.dialect.SQLDialectCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.store.jdbc.ConnectionProvider; +import org.apache.qpid.server.store.jdbc.JDBCSettings; +import org.apache.qpid.server.store.jdbc.JdbcUtils; + +public class JDBCSettingsDrivenConnectionSource extends ConnectionSourceBase +{ + private static final Logger LOGGER = LoggerFactory.getLogger(JDBCSettingsDrivenConnectionSource.class); + + private final ConfiguredObject<?> _object; + private final JDBCSettings _jdbcSettings; + private final AtomicReference<ConnectionProvider> _connectionProvider; + + JDBCSettingsDrivenConnectionSource(final ConfiguredObject<?> object, final JDBCSettings jdbcSettings) + { + _object = object; + _jdbcSettings = jdbcSettings; + _connectionProvider = new AtomicReference<>(); + } + + @Override + public Connection getConnection() throws SQLException + { + final ConnectionProvider connectionProvider = _connectionProvider.get(); + if (connectionProvider == null) + { + throw new IllegalConfigurationException("Connection provider does not exist"); + } + return connectionProvider.getConnection(); + } + + @Override + public void start() + { + _connectionProvider.getAndUpdate(provider -> provider == null ? create() : provider); + discoverConnectionProperties(); + if (!supportsGetGeneratedKeys() && getSQLDialectCode() == SQLDialectCode.UNKNOWN_DIALECT) { + addWarn("Connection does not support GetGeneratedKey method and could not discover the dialect."); + } + super.start(); + } + + @Override + public void stop() + { + super.stop(); + + final ConnectionProvider connectionProvider = _connectionProvider.getAndSet(null); + if (connectionProvider != null) + { + try + { + connectionProvider.close(); + } + catch (SQLException e) + { + LOGGER.warn("Unable to close connection provider", e); + } + } + } + + private ConnectionProvider create() + { + try + { + return JdbcUtils.createConnectionProvider(_object, _jdbcSettings, LOGGER); + } + catch (SQLException e) + { + throw new IllegalConfigurationException("Cannot create connection provider", e); + } + } + + @Override + public String toString() + { + return String.format("JDBCSettingsDrivenConnectionSource{_jdbcSettings=%s}", _jdbcSettings); + } +} diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java similarity index 52% copy from broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java copy to broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java index 7efa4ce..76c125b 100644 --- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLogger.java @@ -17,19 +17,35 @@ * under the License. */ -package org.apache.qpid.server.store.jdbc; +package org.apache.qpid.server.logging.logback.jdbc; -import org.apache.qpid.server.store.Settings; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedContextDefault; +import org.apache.qpid.server.model.VirtualHostLogger; +import org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory; +import org.apache.qpid.server.store.jdbc.JDBCSettings; -public interface JDBCSettings extends Settings +public interface JDBCVirtualHostLogger<X extends JDBCVirtualHostLogger<X>> extends VirtualHostLogger<X>, JDBCSettings { + @Override + @ManagedAttribute(mandatory=true) String getConnectionUrl(); + @Override + @ManagedAttribute(defaultValue= DefaultConnectionProviderFactory.TYPE, + validValues = {"org.apache.qpid.server.store.jdbc.DefaultConnectionProviderFactory#getAllAvailableConnectionProviderTypes()"} ) String getConnectionPoolType(); + @Override + @ManagedAttribute String getUsername(); + @Override + @ManagedAttribute(secure=true) String getPassword(); + @Override + @ManagedAttribute String getTableNamePrefix(); + } diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java new file mode 100644 index 0000000..2a028f6 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImpl.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import java.util.Map; +import java.util.Set; + +import ch.qos.logback.classic.db.DBAppender; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.Context; +import ch.qos.logback.core.status.StatusManager; + +import org.apache.qpid.server.logging.logback.AbstractVirtualHostLogger; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.ManagedObjectFactoryConstructor; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +@SuppressWarnings("unused") +@ManagedObject(category = false, type = JDBCVirtualHostLoggerImpl.CONFIGURED_OBJECT_TYPE, + validChildTypes = "org.apache.qpid.server.logging.logback.AbstractLogger#getSupportedVirtualHostLoggerChildTypes()") +public class JDBCVirtualHostLoggerImpl extends AbstractVirtualHostLogger<JDBCVirtualHostLoggerImpl> + implements JDBCVirtualHostLogger<JDBCVirtualHostLoggerImpl> +{ + static final String CONFIGURED_OBJECT_TYPE = "Jdbc"; + + private final JDBCLoggerHelper _jdbcLoggerHelper; + + private StatusManager _statusManager; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _connectionUrl; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _connectionPoolType; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _username; + + @ManagedAttributeField(afterSet = "restartConnectionSourceIfExists") + private String _password; + + @ManagedAttributeField(afterSet = "restartAppenderIfExists") + private String _tableNamePrefix; + + @ManagedObjectFactoryConstructor + protected JDBCVirtualHostLoggerImpl(final Map<String, Object> attributes, VirtualHost<?> virtualHost) + { + super(attributes, virtualHost); + _jdbcLoggerHelper = new JDBCLoggerHelper(); + } + + @Override + public String getConnectionUrl() + { + return _connectionUrl; + } + + @Override + public String getConnectionPoolType() + { + return _connectionPoolType; + } + + @Override + public String getUsername() + { + return _username; + } + + @Override + public String getPassword() + { + return _password; + } + + @Override + public String getTableNamePrefix() + { + return _tableNamePrefix; + } + + @Override + protected void validateChange(ConfiguredObject<?> proxyForValidation, Set<String> changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + if (changedAttributes.contains(JDBCSettings.CONNECTION_URL) + || changedAttributes.contains(JDBCSettings.USERNAME) + || changedAttributes.contains(JDBCSettings.PASSWORD) + || changedAttributes.contains(JDBCSettings.CONNECTION_POOL_TYPE)) + { + _jdbcLoggerHelper.validateConnectionSourceSettings(this, (JDBCVirtualHostLogger) proxyForValidation); + } + } + + @Override + protected void validateOnCreate() + { + super.validateOnCreate(); + _jdbcLoggerHelper.validateConnectionSourceSettings(this, this); + } + + @Override + protected Appender<ILoggingEvent> createAppenderInstance(final Context context) + { + return _jdbcLoggerHelper.createAppenderInstance(context, this, this); + } + + private void restartAppenderIfExists() + { + _jdbcLoggerHelper.restartAppenderIfExists(getAppender()); + } + + private void restartConnectionSourceIfExists() + { + _jdbcLoggerHelper.restartConnectionSourceIfExists(getAppender()); + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js new file mode 100644 index 0000000..91a40d5 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/add.js @@ -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. + */ +define(["dojo/dom-construct", + "qpid/common/util", + "dojo/parser", + "dojo/text!logger/jdbc/add.html", + "qpid/management/store/pool/ConnectionPool", + "dojo/domReady!"], + function (domConstruct, util, parser, template, ConnectionPool) { + + return { + show: function (data) { + var that = this; + if (data.hasOwnProperty("containerNode")) + { + var containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); + parser.parse(containerNode) + .then(function () { + ConnectionPool.initPoolFieldsInDialog("addLogger", data); + util.applyToWidgets(data.containerNode, data.category, data.type, data.data, data.metadata); + }); + } + } + }; +}); diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js new file mode 100644 index 0000000..d8973cb --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/brokerlogger/jdbc/show.js @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +define(["qpid/common/util", + "dojo/query", + "dojo/text!logger/jdbc/show.html", + "qpid/management/store/pool/ConnectionPool", + "dojo/domReady!"], function (util, query, template, ConnectionPool) { + function BrokerJdbcLogger(params) + { + var that = this; + if (template && params.hasOwnProperty("containerNode")) + { + util.parse(params.containerNode, template, function () { + if (params.hasOwnProperty("metadata")) + { + that.attributeContainers = + util.collectAttributeNodes(params.containerNode, params.metadata, "BrokerLogger", "Jdbc"); + var container = query(".connectionPoolTypeAttributeContainer", params.containerNode)[0]; + that.poolSettings = new ConnectionPool(container, params.management, params.modelObj); + + if (params.hasOwnProperty("data")) + { + that.update(params.data); + } + } + + }); + } + } + + BrokerJdbcLogger.prototype.update = function (data) { + util.updateAttributeNodes(this.attributeContainers, data); + if (this.poolSettings) + { + this.poolSettings.update(data); + } + }; + + return BrokerJdbcLogger; +}); diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js new file mode 100644 index 0000000..435d780 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/add.js @@ -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. + */ +define(["dojo/dom-construct", + "qpid/common/util", + "dojo/parser", + "dojo/text!logger/jdbc/add.html", + "qpid/management/store/pool/ConnectionPool", + "dojo/domReady!"], function (domConstruct, util, parser, template, ConnectionPool) { + return { + show: function (data) { + var that = this; + if (data.hasOwnProperty("containerNode")) + { + var containerNode = domConstruct.create("div", {innerHTML: template}, data.containerNode); + parser.parse(containerNode) + .then(function () { + ConnectionPool.initPoolFieldsInDialog("addLogger", data); + util.applyToWidgets(data.containerNode, data.category, data.type, data.data, data.metadata); + }); + } + } + }; +}); diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js new file mode 100644 index 0000000..69dbda3 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/js/qpid/management/logger/virtualhostlogger/jdbc/show.js @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +define(["qpid/common/util", + "dojo/query", + "dojo/text!logger/jdbc/show.html", + "qpid/management/store/pool/ConnectionPool", + "dojo/domReady!"], function (util, query, template, ConnectionPool) { + + function VirtualHostJdbcLogger(params) + { + var that = this; + if (template && params.hasOwnProperty("containerNode")) + { + util.parse(params.containerNode, template, function () { + if (params.hasOwnProperty("metadata")) + { + that.attributeContainers = + util.collectAttributeNodes(params.containerNode, params.metadata, "VirtualHostLogger", "Jdbc"); + var container = query(".connectionPoolTypeAttributeContainer", params.containerNode)[0]; + that.poolSettings = new ConnectionPool(container, params.management, params.modelObj); + + if (params.hasOwnProperty("data")) + { + that.update(params.data); + } + } + + }); + } + } + + VirtualHostJdbcLogger.prototype.update = function (data) { + util.updateAttributeNodes(this.attributeContainers, data); + if (this.poolSettings) + { + this.poolSettings.update(data); + } + }; + + return VirtualHostJdbcLogger; +}); diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html new file mode 100644 index 0000000..f4fe5d4 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/add.html @@ -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. + --> + +<div> + <div class="formBox clear"> + <fieldset> + <legend>JDBC Settings</legend> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">JDBC Url*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="addLogger.connectionUrl" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'connectionUrl', + placeHolder: 'jdbc:provider:info', + required: true, + missingMessage: 'JDBC URL must be supplied', + title: 'Enter JDBC URL'"/> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Username*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="addLogger.username" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'username', + placeHolder: 'username', + required: true, + missingMessage: 'Username must be supplied', + title: 'Enter username'" /> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Password*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="password" id="addLogger.password" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'password', + placeHolder: 'password', + missingMessage: 'Password must be supplied', + title: 'Enter password'" /> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Connection Pool*:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="addLogger.connectionPoolType" + data-dojo-type="dijit/form/FilteringSelect" + data-dojo-props=" + name: 'connectionPoolType', + required: true, + missingMessage: 'Connection Pool type must be supplied', + title: 'Select Connection Pool', + placeHolder: 'Select pool type'" /> + </div> + </div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Table name prefix:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="addLogger.tableNamePrefix" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'tableNamePrefix', + placeHolder: 'table name prefix', + required: false, + regExp: '[a-zA-Z_0-9]*', + promptMessage: 'Optional database table prefix so multiple loggers can share the same database', + title: 'Optional database table prefix so multiple loggers can share the same database'" /> + </div> + </div> + <div class="clear"></div> + <div id="addLogger.poolSpecificDiv"></div> + </fieldset> + </div> +</div> diff --git a/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html new file mode 100644 index 0000000..026b155 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/main/java/resources/logger/jdbc/show.html @@ -0,0 +1,38 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF licenses this file + ~ to you under the Apache License, Version 2.0 (the + ~ "License"); you may not use this file except in compliance + ~ with the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, + ~ software distributed under the License is distributed on an + ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + ~ KIND, either express or implied. See the License for the + ~ specific language governing permissions and limitations + ~ under the License. + --> +<div> + <div class="clear"> + <div class="formLabel-labelCell">Connection URL:</div> + <div class="connectionUrl"></div> + </div> + <div class="clear usernameAttributeContainer"> + <div class="formLabel-labelCell">Username:</div> + <div class="username"></div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Connection Pool Type:</div> + <div class="connectionPoolType"></div> + </div> + <div class="clear"> + <div class="formLabel-labelCell">Table Name Prefix:</div> + <div class="tableNamePrefix"></div> + </div> + <div class="clear connectionPoolTypeAttributeContainer"></div> + <div class="clear"></div> +</div> diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java new file mode 100644 index 0000000..8af8e83 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/InMemoryDatabaseTestBase.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.After; +import org.junit.Before; + +import org.apache.qpid.test.utils.UnitTestBase; + +public class InMemoryDatabaseTestBase extends UnitTestBase +{ + private Connection _setupConnection; + + @Before + public void startUpDatabase() throws SQLException + { + _setupConnection = DriverManager.getConnection(getTestDatabaseUrl()); + } + + @After + public void shutDownDatabase() throws SQLException + { + try (final Statement statement = _setupConnection.createStatement()) + { + statement.execute("DROP ALL OBJECTS"); + } + finally + { + _setupConnection.close(); + } + } + + String getTestDatabaseUrl() + { + return String.format("jdbc:h2:mem:%s", getTestName()); + } + + protected Connection getConnection() + { + return _setupConnection; + } + +} diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java new file mode 100644 index 0000000..48740ec --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCBrokerLoggerImplTest.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER; +import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelperTest.INVALID_JDBC_URL; +import static org.apache.qpid.server.model.BrokerTestHelper.createBrokerMock; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import ch.qos.logback.classic.db.DBAppender; +import ch.qos.logback.core.Appender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +public class JDBCBrokerLoggerImplTest extends InMemoryDatabaseTestBase +{ + private static final String TABLE_PREFIX = "broker_"; + + private JDBCBrokerLoggerImpl _logger; + + @Before + public void setUp() + { + final Map<String, Object> attributes = new HashMap<>(); + attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName()); + attributes.put(JDBCSettings.CONNECTION_URL, getTestDatabaseUrl()); + _logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock()); + } + + @After + public void tearDown() + { + if (_logger != null) + { + _logger.close(); + } + } + + @Test + public void createAppenderOnCreate() + { + _logger.create(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertTrue(appender instanceof DBAppender); + } + + @Test + public void createAppenderOnOpen() + { + _logger.open(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertTrue(appender instanceof DBAppender); + } + + @Test + public void closeAndReopenLogger() + { + _logger.create(); + _logger.close(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertNotNull(appender); + _logger.open(); + assertSame(appender, ROOT_LOGGER.getAppender(getTestName())); + } + + @Test + public void detachAppenderInstanceOnDelete() + { + _logger.create(); + _logger.delete(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertNull(appender); + } + + @Test + public void createLoggerWithInvalidURL() + { + final Map<String, Object> attributes = new HashMap<>(); + attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName()); + attributes.put(JDBCSettings.CONNECTION_URL, INVALID_JDBC_URL); + final JDBCBrokerLoggerImpl logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock()); + try + { + logger.create(); + fail("Exception should be thrown"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } + + @Test + public void changeLoggerURLtoInvalid() + { + _logger.create(); + final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.CONNECTION_URL, INVALID_JDBC_URL); + try + { + _logger.setAttributes(attributes); + fail("Exception should be thrown"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } + + @Test + public void changeTablePrefix() + { + _logger.create(); + + final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.TABLE_NAME_PREFIX, TABLE_PREFIX); + _logger.setAttributes(attributes); + + assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix()); + } + +} diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java new file mode 100644 index 0000000..0e03e47 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCLoggerHelperTest.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.db.DBAppender; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.db.ConnectionSource; +import org.junit.Before; +import org.junit.Test; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerTestHelper; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +public class JDBCLoggerHelperTest extends InMemoryDatabaseTestBase +{ + static final String INVALID_JDBC_URL = "jdbc:invalid"; + private JDBCSettings _jdbcSettings; + private JDBCLoggerHelper _jdbcLoggerHelper; + private Broker<?> _broker; + + @Before + public void setUp() + { + _jdbcSettings = mock(JDBCSettings.class); + when(_jdbcSettings.getConnectionUrl()).thenReturn(getTestDatabaseUrl()); + _jdbcLoggerHelper = new JDBCLoggerHelper(); + _broker = BrokerTestHelper.createBrokerMock(); + } + + @Test + public void createAppenderInstance() + { + final LoggerContext context = ROOT_LOGGER.getLoggerContext(); + final Appender<ILoggingEvent> appender = + _jdbcLoggerHelper.createAppenderInstance(context, _broker, _jdbcSettings); + assertTrue(appender instanceof DBAppender); + assertTrue(appender.isStarted()); + assertEquals(context, appender.getContext()); + assertTrue(((DBAppender)appender).getConnectionSource() instanceof JDBCSettingsDrivenConnectionSource); + } + + @Test + public void restartAppenderIfExists() + { + final Appender appender = mock(Appender.class); + _jdbcLoggerHelper.restartAppenderIfExists(appender); + verify(appender).stop(); + verify(appender).start(); + verifyNoMoreInteractions(appender); + } + + @Test + public void restartConnectionSourceIfExists() + { + final ConnectionSource connectionSource = mock(ConnectionSource.class); + final DBAppender appender = mock(DBAppender.class); + when(appender.getConnectionSource()).thenReturn(connectionSource); + _jdbcLoggerHelper.restartConnectionSourceIfExists(appender); + verify(connectionSource).stop(); + verify(connectionSource).start(); + verifyNoMoreInteractions(connectionSource); + } + + @Test + public void validateConnectionSourceSettings() + { + _jdbcLoggerHelper.validateConnectionSourceSettings(_broker, _jdbcSettings); + } + + @Test + public void validateConnectionSourceSettingsForInvalidURL() + { + when(_jdbcSettings.getConnectionUrl()).thenReturn(INVALID_JDBC_URL); + try + { + _jdbcLoggerHelper.validateConnectionSourceSettings(_broker, _jdbcSettings); + fail("Exception is expected"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java new file mode 100644 index 0000000..4da137f --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDBNameResolverTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import ch.qos.logback.classic.db.names.ColumnName; +import ch.qos.logback.classic.db.names.TableName; +import org.junit.Before; +import org.junit.Test; + +import org.apache.qpid.server.store.jdbc.JDBCSettings; +import org.apache.qpid.test.utils.UnitTestBase; + +public class JDBCSettingsDBNameResolverTest extends UnitTestBase +{ + private static final String TABLE_PREFIX = "test_"; + private JDBCSettingsDBNameResolver _dbNameResolver; + + @Before + public void setUp() + { + final JDBCSettings jdbcSettings = mock(JDBCSettings.class); + when(jdbcSettings.getTableNamePrefix()).thenReturn(TABLE_PREFIX); + _dbNameResolver = new JDBCSettingsDBNameResolver(jdbcSettings); + } + + @Test + public void getTableName() + { + assertEquals((TABLE_PREFIX + TableName.LOGGING_EVENT.name()).toLowerCase(), + _dbNameResolver.getTableName(TableName.LOGGING_EVENT)); + } + + @Test + public void getColumnName() + { + assertEquals(ColumnName.LOGGER_NAME.name().toLowerCase(), + _dbNameResolver.getColumnName(ColumnName.LOGGER_NAME)); + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java new file mode 100644 index 0000000..0120452 --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCSettingsDrivenConnectionSourceTest.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +public class JDBCSettingsDrivenConnectionSourceTest extends InMemoryDatabaseTestBase +{ + private JDBCSettingsDrivenConnectionSource _connectionSource; + + @Before + public void setUp() + { + final JDBCSettings jdbcSettings = mock(JDBCSettings.class); + when(jdbcSettings.getConnectionUrl()).thenReturn( getTestDatabaseUrl()); + + final ConfiguredObject<?> object = mock(ConfiguredObject.class); + _connectionSource = new JDBCSettingsDrivenConnectionSource(object, jdbcSettings); + _connectionSource.setContext(ROOT_LOGGER.getLoggerContext()); + } + + @After + public void tearDown() + { + if (_connectionSource != null) + { + _connectionSource.stop(); + } + } + + @Test + public void testStart() throws SQLException + { + try + { + _connectionSource.getConnection(); + fail("connection should fail for non started ConnectionSource"); + } + catch (IllegalConfigurationException e) + { + // pass + } + + _connectionSource.start(); + + final Connection connection = _connectionSource.getConnection(); + connection.close(); + } + + @Test + public void testStop() throws SQLException + { + _connectionSource.start(); + _connectionSource.stop(); + try + { + _connectionSource.getConnection(); + fail("connection should fail for stopped ConnectionSource"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } + + @Test + public void testGetConnection() throws SQLException + { + _connectionSource.start(); + final Connection connection = _connectionSource.getConnection(); + connection.close(); + } +} diff --git a/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java new file mode 100644 index 0000000..ce3b00c --- /dev/null +++ b/broker-plugins/jdbc-logging-logback/src/test/java/org/apache/qpid/server/logging/logback/jdbc/JDBCVirtualHostLoggerImplTest.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback.jdbc; + +import static org.apache.qpid.server.logging.logback.jdbc.JDBCLoggerHelper.ROOT_LOGGER; +import static org.apache.qpid.server.model.BrokerTestHelper.createBrokerMock; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import ch.qos.logback.classic.db.DBAppender; +import ch.qos.logback.core.Appender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.BrokerTestHelper; +import org.apache.qpid.server.store.jdbc.JDBCSettings; + +public class JDBCVirtualHostLoggerImplTest extends InMemoryDatabaseTestBase +{ + private static final String TABLE_PREFIX = "vh_"; + + private JDBCVirtualHostLoggerImpl _logger; + + @Before + public void setUp() throws Exception + { + final Map<String, Object> attributes = new HashMap<>(); + attributes.put(JDBCVirtualHostLoggerImpl.NAME, getTestName()); + attributes.put(JDBCSettings.CONNECTION_URL, getTestDatabaseUrl()); + _logger = new JDBCVirtualHostLoggerImpl(attributes, BrokerTestHelper.createVirtualHost(getTestName(), this)); + } + + @After + public void tearDown() + { + if (_logger != null) + { + _logger.close(); + } + } + + @Test + public void createAppenderOnCreate() + { + _logger.create(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertTrue(appender instanceof DBAppender); + } + + @Test + public void createAppenderOnOpen() + { + _logger.open(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertTrue(appender instanceof DBAppender); + } + + @Test + public void detachAppenderInstanceOnDelete() + { + _logger.create(); + _logger.delete(); + final Appender appender = ROOT_LOGGER.getAppender(getTestName()); + assertNull(appender); + } + + @Test + public void createLoggerWithInvalidURL() + { + final Map<String, Object> attributes = new HashMap<>(); + attributes.put(JDBCBrokerLoggerImpl.NAME, getTestName()); + attributes.put(JDBCSettings.CONNECTION_URL, JDBCLoggerHelperTest.INVALID_JDBC_URL); + final JDBCBrokerLoggerImpl logger = new JDBCBrokerLoggerImpl(attributes, createBrokerMock()); + try + { + logger.create(); + fail("Exception should be thrown"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } + + @Test + public void changeLoggerURLtoInvalid() + { + _logger.create(); + final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.CONNECTION_URL, + JDBCLoggerHelperTest.INVALID_JDBC_URL); + try + { + _logger.setAttributes(attributes); + fail("Exception should be thrown"); + } + catch (IllegalConfigurationException e) + { + // pass + } + } + + @Test + public void changeTablePrefix() + { + _logger.create(); + + final Map<String, Object> attributes = Collections.singletonMap(JDBCSettings.TABLE_NAME_PREFIX, TABLE_PREFIX); + _logger.setAttributes(attributes); + + assertEquals(TABLE_PREFIX, _logger.getTableNamePrefix()); + } + +} diff --git a/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js b/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js index 0297165..9cc166a 100644 --- a/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js +++ b/broker-plugins/jdbc-provider-bone/src/main/java/resources/js/qpid/management/store/pool/bonecp/show.js @@ -26,7 +26,8 @@ define(["dojo/_base/xhr", "dojo/parser", "dojox/html/entities", "dojo/query", "d function BoneCP(data) { var containerNode = data.containerNode; - this.parent = data.parent; + this.management = data.management ? data.management : data.parent.management; + this.modelObj = data.modelObj ? data.modelObj : data.parent.modelObj; var that = this; xhr.get({ url: "store/pool/bonecp/show.html", @@ -57,7 +58,7 @@ define(["dojo/_base/xhr", "dojo/parser", "dojox/html/entities", "dojo/query", "d BoneCP.prototype._update = function (data) { - this.parent.management.load(this.parent.modelObj, + this.management.load(this.modelObj, { excludeInheritedContext: false, depth: 0 diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java index 7efa4ce..01ee196 100644 --- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java +++ b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JDBCSettings.java @@ -23,6 +23,12 @@ import org.apache.qpid.server.store.Settings; public interface JDBCSettings extends Settings { + String CONNECTION_URL = "connectionUrl"; + String CONNECTION_POOL_TYPE = "connectionPoolType"; + String USERNAME = "username"; + String PASSWORD = "password"; + String TABLE_NAME_PREFIX = "tableNamePrefix"; + String getConnectionUrl(); String getConnectionPoolType(); diff --git a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java index d3df9ae..a23b362 100644 --- a/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java +++ b/broker-plugins/jdbc-store/src/main/java/org/apache/qpid/server/store/jdbc/JdbcUtils.java @@ -80,9 +80,11 @@ public class JdbcUtils } - static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent, final Logger logger) + public static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent, + final JDBCSettings settings, + final Logger logger) + throws SQLException { - JDBCSettings settings = (JDBCSettings) parent; String connectionPoolType = settings.getConnectionPoolType() == null ? DefaultConnectionProviderFactory.TYPE : settings.getConnectionPoolType(); @@ -95,20 +97,26 @@ public class JdbcUtils connectionProviderFactory = new DefaultConnectionProviderFactory(); } - try + Map<String, String> providerAttributes = new HashMap<>(); + Set<String> providerAttributeNames = new HashSet<>(connectionProviderFactory.getProviderAttributeNames()); + providerAttributeNames.retainAll(parent.getContextKeys(false)); + for (String attr : providerAttributeNames) { - Map<String, String> providerAttributes = new HashMap<>(); - Set<String> providerAttributeNames = new HashSet<>(connectionProviderFactory.getProviderAttributeNames()); - providerAttributeNames.retainAll(parent.getContextKeys(false)); - for (String attr : providerAttributeNames) - { - providerAttributes.put(attr, parent.getContextValue(String.class, attr)); - } + providerAttributes.put(attr, parent.getContextValue(String.class, attr)); + } - return connectionProviderFactory.getConnectionProvider(settings.getConnectionUrl(), - settings.getUsername(), - settings.getPassword(), - providerAttributes); + return connectionProviderFactory.getConnectionProvider(settings.getConnectionUrl(), + settings.getUsername(), + settings.getPassword(), + providerAttributes); + } + + static ConnectionProvider createConnectionProvider(final ConfiguredObject<?> parent, final Logger logger) + { + JDBCSettings settings = (JDBCSettings) parent; + try + { + return createConnectionProvider(parent, settings, logger); } catch (SQLException e) { diff --git a/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js b/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js new file mode 100644 index 0000000..79b9ee2 --- /dev/null +++ b/broker-plugins/jdbc-store/src/main/java/resources/js/qpid/management/store/pool/ConnectionPool.js @@ -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. + */ + +define(["qpid/common/util", + "dijit/registry", + "dojo/_base/array", + "dojo/dom-construct", + "dojo/dom", + "dojo/string"], + function (util, registry, array, domConstruct, dom, string) { + + function ConnectionPool(container, management, modelObj) + { + this.containerNode = container; + this.previousConnectionPoolType = null; + this.management = management; + this.modelObj = modelObj; + this.poolDetails = null; + } + + ConnectionPool.prototype.update = function (data) { + if (data && data.hasOwnProperty("connectionPoolType") + && (!this.poolDetails || this.previousConnectionPoolType !== data.connectionPoolType)) + { + var that = this; + require(["qpid/management/store/pool/" + data.connectionPoolType.toLowerCase() + "/show"], + function (PoolDetails) { + that.poolDetails = that._createPoolDetails(PoolDetails); + that.previousConnectionPoolType = data.connectionPoolType; + that.poolDetails.update(data); + }); + } + else + { + this.poolDetails.update(data); + } + }; + + ConnectionPool.prototype._createPoolDetails = function (PoolDetails) { + var widgets = registry.findWidgets(this.containerNode); + array.forEach(widgets, function (item) { + item.destroyRecursive(); + }); + domConstruct.empty(this.containerNode); + + return new PoolDetails({ + containerNode: this.containerNode, + management: this.management, + modelObj: this.modelObj + }); + }; + + ConnectionPool.initPoolFieldsInDialog = function (dialogIdPrefix, data) { + registry.byId(dialogIdPrefix + ".connectionUrl") + .set("regExpGen", util.jdbcUrlOrContextVarRegexp); + registry.byId(dialogIdPrefix + ".username") + .set("regExpGen", util.nameOrContextVarRegexp); + + var passwordControl = registry.byId(dialogIdPrefix + ".password"); + passwordControl.set("required", !data.data); + + var poolTypeControl = registry.byId(dialogIdPrefix + ".connectionPoolType"); + + var typeMetaData = data.metadata.getMetaData(data.category, data.type); + var values = ["NONE"]; + if (typeMetaData.attributes.hasOwnProperty("connectionPoolType") + && typeMetaData.attributes.connectionPoolType.hasOwnProperty("validValues")) + { + values = typeMetaData.attributes.connectionPoolType.validValues; + } + var store = util.makeTypeStore(values); + poolTypeControl.set("store", store); + poolTypeControl.set("value", "NONE"); + + var poolTypeFieldsDiv = dom.byId(dialogIdPrefix + ".poolSpecificDiv"); + poolTypeControl.on("change", function (type) { + if (type && string.trim(type) !== "") + { + var widgets = registry.findWidgets(poolTypeFieldsDiv); + array.forEach(widgets, function (item) { + item.destroyRecursive(); + }); + widgets.forEach(function (item) { + item.destroyRecursive(); + }); + domConstruct.empty(poolTypeFieldsDiv); + require(["qpid/management/store/pool/" + type.toLowerCase() + "/add"], function (poolType) { + poolType.show({ + containerNode: poolTypeFieldsDiv, + context: data.context + }); + }); + } + }); + }; + return ConnectionPool; + }); diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java index 90296da..071309e 100644 --- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java +++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java @@ -127,7 +127,7 @@ public abstract class AbstractLogger<X extends AbstractLogger<X>> extends Abstra public void stopLogging() { - Appender appender = ROOT_LOGGER.getAppender(getName()); + final Appender appender = getAppender(); if (appender != null) { appender.stop(); @@ -135,6 +135,11 @@ public abstract class AbstractLogger<X extends AbstractLogger<X>> extends Abstra } } + protected Appender<ILoggingEvent> getAppender() + { + return ROOT_LOGGER.getAppender(getName()); + } + private class LogInclusionRuleListener extends AbstractConfigurationChangeListener { diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java index a6a4031..0338e38 100644 --- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java +++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerImpl.java @@ -34,16 +34,12 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.Context; import ch.qos.logback.core.rolling.RollingFileAppender; -import ch.qos.logback.core.status.Status; import ch.qos.logback.core.status.StatusListener; import ch.qos.logback.core.status.StatusManager; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.qpid.server.logging.LogFileDetails; -import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Content; @@ -56,8 +52,6 @@ import org.apache.qpid.server.util.DaemonThreadFactory; public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerImpl> implements BrokerFileLogger<BrokerFileLoggerImpl>, FileLoggerSettings { - private static final Logger LOGGER = LoggerFactory.getLogger(BrokerFileLoggerImpl.class); - private volatile RolloverWatcher _rolloverWatcher; private ScheduledExecutorService _rolledPolicyExecutor; @@ -200,7 +194,11 @@ public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerI protected Appender<ILoggingEvent> createAppenderInstance(Context loggerContext) { SystemConfig<?> systemConfig = getAncestor(SystemConfig.class); - _logbackStatusListener = new BrokerFileLoggerStatusListener(this, systemConfig); + _logbackStatusListener = new BrokerLoggerStatusListener(this, + systemConfig, + BROKER_FAIL_ON_LOGGER_IO_ERROR, + IOException.class, + IOError.class); _statusManager = loggerContext.getStatusManager(); _statusManager.add(_logbackStatusListener); @@ -232,41 +230,5 @@ public class BrokerFileLoggerImpl extends AbstractBrokerLogger<BrokerFileLoggerI } } - static class BrokerFileLoggerStatusListener implements StatusListener - { - private final SystemConfig<?> _systemConfig; - private final BrokerFileLogger<?> _brokerFileLogger; - - public BrokerFileLoggerStatusListener(BrokerFileLogger<?> brokerFileLogger, SystemConfig<?> systemConfig) - { - _brokerFileLogger = brokerFileLogger; - _systemConfig = systemConfig; - } - - @Override - public void addStatusEvent(Status status) - { - Throwable throwable = status.getThrowable(); - if (status.getEffectiveLevel() == Status.ERROR - && (throwable instanceof IOException || throwable instanceof IOError)) - { - LOGGER.error("Unexpected I/O error whilst trying to write to log file. Log messages could be lost.", throwable); - if (_brokerFileLogger.getContextValue(Boolean.class, BROKER_FAIL_ON_LOGGER_IO_ERROR)) - { - try - { - _brokerFileLogger.stopLogging(); - _systemConfig.getEventLogger().message(BrokerMessages.FATAL_ERROR( - String.format("Shutting down the broker because context variable '%s' is set and unexpected i/o issue occurred: %s", - BROKER_FAIL_ON_LOGGER_IO_ERROR, throwable.getMessage()))); - } - finally - { - _systemConfig.closeAsync(); - } - } - } - } - } } diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java new file mode 100644 index 0000000..7497953 --- /dev/null +++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListener.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.logging.logback; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; + +import ch.qos.logback.core.status.Status; +import ch.qos.logback.core.status.StatusListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.model.BrokerLogger; +import org.apache.qpid.server.model.SystemConfig; + +public class BrokerLoggerStatusListener implements StatusListener +{ + private static final Logger LOGGER = LoggerFactory.getLogger(BrokerLoggerStatusListener.class); + + private final SystemConfig<?> _systemConfig; + private final BrokerLogger<?> _brokerLogger; + private final String _contextFlag; + private final Set<Class<?>> _errorClasses; + + public BrokerLoggerStatusListener(final BrokerLogger<?> brokerLogger, + final SystemConfig<?> systemConfig, + final String contextFlag, + final Class<?>... errorClass) + { + _brokerLogger = brokerLogger; + _systemConfig = systemConfig; + _contextFlag = contextFlag; + _errorClasses = + errorClass == null ? Collections.emptySet() : Arrays.stream(errorClass).collect(Collectors.toSet()); + } + + @Override + public void addStatusEvent(Status status) + { + Throwable throwable = status.getThrowable(); + if (status.getEffectiveLevel() == Status.ERROR + && _errorClasses.stream().anyMatch(c -> c.isInstance(throwable))) + { + LOGGER.error("Unexpected error whilst trying to store log entry. Log messages could be lost.", throwable); + if (_brokerLogger.getContextValue(Boolean.class, _contextFlag)) + { + try + { + _brokerLogger.stopLogging(); + _systemConfig.getEventLogger().message(BrokerMessages.FATAL_ERROR( + String.format( + "Shutting down the broker because context variable '%s' is set and unexpected logging issue occurred: %s", + _contextFlag, + throwable.getMessage()))); + } + finally + { + _systemConfig.closeAsync(); + } + } + } + } +} diff --git a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java similarity index 87% rename from broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java rename to broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java index 6645fcb..7cd0329 100644 --- a/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerFileLoggerStatusListenerTest.java +++ b/broker-plugins/logging-logback/src/test/java/org/apache/qpid/server/logging/logback/BrokerLoggerStatusListenerTest.java @@ -37,9 +37,9 @@ import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.model.SystemConfig; import org.apache.qpid.test.utils.UnitTestBase; -public class BrokerFileLoggerStatusListenerTest extends UnitTestBase +public class BrokerLoggerStatusListenerTest extends UnitTestBase { - private BrokerFileLoggerImpl.BrokerFileLoggerStatusListener _statusListener; + private BrokerLoggerStatusListener _statusListener; private BrokerFileLogger<?> _fileLogger; private SystemConfig<?> _systemConfig; @@ -50,12 +50,12 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase _systemConfig = mock(SystemConfig.class); EventLogger eventLogger = mock(EventLogger.class); when(_systemConfig.getEventLogger()).thenReturn(eventLogger); - _statusListener = new BrokerFileLoggerImpl.BrokerFileLoggerStatusListener(_fileLogger, _systemConfig); + _statusListener = new BrokerLoggerStatusListener(_fileLogger, _systemConfig, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR, IOException.class, IOError.class); when(_fileLogger.getContextValue(Boolean.class, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(true); } @Test - public void testAddStatusEventForIOError() throws Exception + public void testAddStatusEventForIOError() { Status event = createEvent(new IOError(new IOException("Mocked: No disk space left")), Status.ERROR); _statusListener.addStatusEvent(event); @@ -64,7 +64,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase } @Test - public void testAddStatusEventForIOErrorWithFailOnLoggerIOErrorDisabled() throws Exception + public void testAddStatusEventForIOErrorWithFailOnLoggerIOErrorDisabled() { Status event = createEvent(new IOError(new IOException("Mocked: No disk space left")), Status.ERROR); when(_fileLogger.getContextValue(Boolean.class, BrokerFileLogger.BROKER_FAIL_ON_LOGGER_IO_ERROR)).thenReturn(false); @@ -74,7 +74,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase } @Test - public void testAddStatusEventForIOException() throws Exception + public void testAddStatusEventForIOException() { Status event = createEvent(new IOException("Mocked: No disk space left"), Status.ERROR); _statusListener.addStatusEvent(event); @@ -83,7 +83,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase } @Test - public void testAddStatusEventForIOExceptionReportedAsWarning() throws Exception + public void testAddStatusEventForIOExceptionReportedAsWarning() { Status event = createEvent(new IOException("Mocked: No disk space left"), Status.WARN); _statusListener.addStatusEvent(event); @@ -92,7 +92,7 @@ public class BrokerFileLoggerStatusListenerTest extends UnitTestBase } @Test - public void testAddStatusEventForNonIOException() throws Exception + public void testAddStatusEventForNonIOException() { Status event = createEvent(new RuntimeException("Mocked: No disk space left"), Status.ERROR); _statusListener.addStatusEvent(event); diff --git a/broker-plugins/management-http/src/main/java/resources/addLogger.html b/broker-plugins/management-http/src/main/java/resources/addLogger.html index 04f70de..c0aa6b5 100644 --- a/broker-plugins/management-http/src/main/java/resources/addLogger.html +++ b/broker-plugins/management-http/src/main/java/resources/addLogger.html @@ -69,6 +69,11 @@ <div id="addLogger.typeFields"></div> </div> <div class="clear"></div> + <div data-dojo-type="dijit/TitlePane" data-dojo-props="title: 'Context variables', open: false"> + <div id="addLogger.context" + data-dojo-type="qpid.common.ContextVariablesEditor" + data-dojo-props="name: 'context', title: 'Context variables'"></div> + </div> </div> <div class="dijitDialogPaneActionBar qpidDialogPaneActionBar"> <button data-dojo-type="dijit/form/Button" id="addLogger.addButton" data-dojo-props="label: 'Save'" type="submit"></button> diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js index 44ac1d2..9c368ae 100644 --- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js +++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addLogger.js @@ -30,6 +30,7 @@ define(["dojo/_base/lang", 'dojo/json', "qpid/common/util", "dojo/text!addLogger.html", + "qpid/common/ContextVariablesEditor", "dojo/store/Memory", "dojox/validate/us", "dojox/validate/web", @@ -92,6 +93,7 @@ define(["dojo/_base/lang", this.categoryFieldsContainer = dom.byId("addLogger.categoryFields"); this.allFieldsContainer = dom.byId("addLogger.contentPane"); + this.context = registry.byId("addLogger.context"); }, show: function (management, modelObj, category, actualData) { @@ -119,12 +121,18 @@ define(["dojo/_base/lang", var virtualHostlLoggerEditWarningNode = dom.byId("virtualHostlLoggerEditWarning"); domStyle.set(brokerLoggerEditWarningNode, "display", - !this.isNew && this.category == "BrokerLogger" ? "block" : "none"); + !this.isNew && this.category === "BrokerLogger" ? "block" : "none"); domStyle.set(virtualHostlLoggerEditWarningNode, "display", - !this.isNew && this.category == "VirtualHostLogger" ? "block" : "none"); + !this.isNew && this.category === "VirtualHostLogger" ? "block" : "none"); - this._loadCategoryUserInterfacesAndShowDialog(actualData); + util.loadEffectiveAndInheritedActualData(this.management, this.modelObj, lang.hitch(this, function(data) + { + this.context.setData(this.isNew ? {} : this.initialData.context , + data.effective.context, + data.inheritedActual.context); + this._loadCategoryUserInterfacesAndShowDialog(actualData); + })); }, hide: function () { @@ -150,6 +158,16 @@ define(["dojo/_base/lang", || this.management.metadata.getDefaultValueForType(this.category, this.loggerType.get("value")); var formData = util.getFormWidgetValues(this.form, excludedData); + var context = this.context.get("value"); + var oldContext = null; + if (this.initialData !== null && this.initialData !== undefined) + { + oldContext = this.initialData.context; + } + if (context && !util.equals(context, oldContext)) + { + formData["context"] = context; + } var that = this; if (this.isNew) { @@ -200,7 +218,8 @@ define(["dojo/_base/lang", data: that.initialData, metadata: that.management.metadata, category: that.category, - type: type + type: type, + context: that.context }); if (promise) { diff --git a/broker/pom.xml b/broker/pom.xml index 66fb2e5..e5340bd 100644 --- a/broker/pom.xml +++ b/broker/pom.xml @@ -111,6 +111,12 @@ <dependency> <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.apache.qpid</groupId> <artifactId>qpid-broker-plugins-amqp-1-0-protocol-jdbc-link-store</artifactId> <scope>runtime</scope> </dependency> diff --git a/pom.xml b/pom.xml index 0cd07df..1a851ab 100644 --- a/pom.xml +++ b/pom.xml @@ -151,6 +151,7 @@ <buildnumber-maven-plugin-version>1.4</buildnumber-maven-plugin-version> <maven-jar-plugin-version>3.1.0</maven-jar-plugin-version> <maven-surefire-report-plugin-version>2.22.0</maven-surefire-report-plugin-version> + <h2.version>1.4.199</h2.version> </properties> <modules> @@ -168,6 +169,7 @@ <module>broker-plugins/derby-store</module> <module>broker-plugins/jdbc-provider-bone</module> <module>broker-plugins/jdbc-store</module> + <module>broker-plugins/jdbc-logging-logback</module> <module>broker-plugins/logging-logback</module> <module>broker-plugins/management-amqp</module> <module>broker-plugins/management-http</module> @@ -347,6 +349,12 @@ <dependency> <groupId>org.apache.qpid</groupId> + <artifactId>qpid-broker-plugins-jdbc-logging-logback</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.qpid</groupId> <artifactId>qpid-broker-plugins-memory-store</artifactId> <version>${project.version}</version> </dependency> --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org