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    }