    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements. See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache license, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License. You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the license for the specific language governing permissions and
    015     * limitations under the license.
    016     */
    017
    018    package org.apache.logging.log4j.core.appender.mom;
    019
    020    import java.io.Serializable;
    021    import javax.jms.Connection;
    022    import javax.jms.ConnectionFactory;
    023    import javax.jms.Destination;
    024    import javax.jms.JMSException;
    025    import javax.jms.Message;
    026    import javax.jms.MessageConsumer;
    027    import javax.jms.MessageProducer;
    028    import javax.jms.Session;
    029    import javax.naming.NamingException;
    030
    031    import org.apache.logging.log4j.Logger;
    032    import org.apache.logging.log4j.core.appender.AbstractManager;
    033    import org.apache.logging.log4j.core.appender.ManagerFactory;
    034    import org.apache.logging.log4j.core.net.JndiManager;
    035    import org.apache.logging.log4j.status.StatusLogger;
    036
    037    /**
    038     * JMS connection and session manager. Can be used to access MessageProducer, MessageConsumer, and Message objects
    039     * involving a configured ConnectionFactory and Destination.
    040     */
    041    public class JmsManager extends AbstractManager {
    042
    043        private static final Logger LOGGER = StatusLogger.getLogger();
    044
    045        private static final JmsManagerFactory FACTORY = new JmsManagerFactory();
    046
    047        private final JndiManager jndiManager;
    048        private final Connection connection;
    049        private final Session session;
    050        private final Destination destination;
    051
    052        private JmsManager(final String name, final JndiManager jndiManager, final String connectionFactoryName,
    053                           final String destinationName, final String username, final String password)
    054            throws NamingException, JMSException {
    055            super(name);
    056            this.jndiManager = jndiManager;
    057            final ConnectionFactory connectionFactory = this.jndiManager.lookup(connectionFactoryName);
    058            if (username != null && password != null) {
    059                this.connection = connectionFactory.createConnection(username, password);
    060            } else {
    061                this.connection = connectionFactory.createConnection();
    062            }
    063            this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    064            this.destination = this.jndiManager.lookup(destinationName);
    065            this.connection.start();
    066        }
    067
    068        /**
    069         * Gets a JmsManager using the specified configuration parameters.
    070         *
    071         * @param name                  The name to use for this JmsManager.
    072         * @param jndiManager           The JndiManager to look up JMS information through.
    073         * @param connectionFactoryName The binding name for the {@link javax.jms.ConnectionFactory}.
    074         * @param destinationName       The binding name for the {@link javax.jms.Destination}.
    075         * @param username              The username to connect with or {@code null} for no authentication.
    076         * @param password              The password to use with the given username or {@code null} for no authentication.
    077         * @return The JmsManager as configured.
    078         */
    079        public static JmsManager getJmsManager(final String name, final JndiManager jndiManager,
    080                                               final String connectionFactoryName, final String destinationName,
    081                                               final String username, final String password) {
    082            final JmsConfiguration configuration = new JmsConfiguration(jndiManager, connectionFactoryName, destinationName,
    083                username, password);
    084            return FACTORY.createManager(name, configuration);
    085        }
    086
    087        /**
    088         * Creates a MessageConsumer on this Destination using the current Session.
    089         *
    090         * @return A MessageConsumer on this Destination.
    091         * @throws JMSException
    092         */
    093        public MessageConsumer createMessageConsumer() throws JMSException {
    094            return this.session.createConsumer(this.destination);
    095        }
    096
    097        /**
    098         * Creates a MessageProducer on this Destination using the current Session.
    099         *
    100         * @return A MessageProducer on this Destination.
    101         * @throws JMSException
    102         */
    103        public MessageProducer createMessageProducer() throws JMSException {
    104            return this.session.createProducer(this.destination);
    105        }
    106
    107        /**
    108         * Creates a TextMessage or ObjectMessage from a Serializable object. For instance, when using a text-based
    109         * {@link org.apache.logging.log4j.core.Layout} such as {@link org.apache.logging.log4j.core.layout.PatternLayout},
    110         * the {@link org.apache.logging.log4j.core.LogEvent} message will be serialized to a String. When using a
    111         * layout such as {@link org.apache.logging.log4j.core.layout.SerializedLayout}, the LogEvent message will be
    112         * serialized as a Java object.
    113         *
    114         * @param object The LogEvent or String message to wrap.
    115         * @return A new JMS message containing the provided object.
    116         * @throws JMSException
    117         */
    118        public Message createMessage(final Serializable object) throws JMSException {
    119            if (object instanceof String) {
    120                return this.session.createTextMessage((String) object);
    121            }
    122            return this.session.createObjectMessage(object);
    123        }
    124
    125        @Override
    126        protected void releaseSub() {
    127            try {
    128                this.session.close();
    129            } catch (final JMSException ignored) {
    130            }
    131            try {
    132                this.connection.close();
    133            } catch (final JMSException ignored) {
    134            }
    135            this.jndiManager.release();
    136        }
    137
    138        private static class JmsConfiguration {
    139            private final JndiManager jndiManager;
    140            private final String connectionFactoryName;
    141            private final String destinationName;
    142            private final String username;
    143            private final String password;
    144
    145            private JmsConfiguration(final JndiManager jndiManager, final String connectionFactoryName, final String destinationName,
    146                                     final String username, final String password) {
    147                this.jndiManager = jndiManager;
    148                this.connectionFactoryName = connectionFactoryName;
    149                this.destinationName = destinationName;
    150                this.username = username;
    151                this.password = password;
    152            }
    153        }
    154
    155        private static class JmsManagerFactory implements ManagerFactory<JmsManager, JmsConfiguration> {
    156
    157            @Override
    158            public JmsManager createManager(final String name, final JmsConfiguration data) {
    159                try {
    160                    return new JmsManager(name, data.jndiManager, data.connectionFactoryName, data.destinationName,
    161                        data.username, data.password);
    162                } catch (final Exception e) {
    163                    LOGGER.error("Error creating JmsManager using ConnectionFactory [{}] and Destination [{}].",
    164                        data.connectionFactoryName, data.destinationName, e);
    165                    return null;
    166                }
    167            }
    168        }
    169
    170    }