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
018package org.apache.logging.log4j.core.appender.mom;
019
020import java.io.Serializable;
021import javax.jms.JMSException;
022import javax.jms.Message;
023import javax.jms.MessageProducer;
024
025import org.apache.logging.log4j.core.Appender;
026import org.apache.logging.log4j.core.Filter;
027import org.apache.logging.log4j.core.Layout;
028import org.apache.logging.log4j.core.LogEvent;
029import org.apache.logging.log4j.core.appender.AbstractAppender;
030import org.apache.logging.log4j.core.appender.AppenderLoggingException;
031import org.apache.logging.log4j.core.config.Node;
032import org.apache.logging.log4j.core.config.plugins.Plugin;
033import org.apache.logging.log4j.core.config.plugins.PluginAliases;
034import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
035import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
036import org.apache.logging.log4j.core.config.plugins.PluginElement;
037import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
038import org.apache.logging.log4j.core.layout.SerializedLayout;
039import org.apache.logging.log4j.core.net.JndiManager;
040
041/**
042 * Generic JMS Appender plugin for both queues and topics. This Appender replaces the previous split ones. However,
043 * configurations set up for the 2.0 version of the JMS appenders will still work.
044 */
045@Plugin(name = "JMS", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true)
046@PluginAliases({"JMSQueue", "JMSTopic"})
047public class JmsAppender extends AbstractAppender {
048
049    private final JmsManager manager;
050    private final MessageProducer producer;
051
052    protected JmsAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
053                        final boolean ignoreExceptions, final JmsManager manager)
054        throws JMSException {
055        super(name, filter, layout, ignoreExceptions);
056        this.manager = manager;
057        this.producer = this.manager.createMessageProducer();
058    }
059
060    @Override
061    public void append(final LogEvent event) {
062        try {
063            final Message message = this.manager.createMessage(getLayout().toSerializable(event));
064            message.setJMSTimestamp(event.getTimeMillis());
065            this.producer.send(message);
066        } catch (final JMSException e) {
067            throw new AppenderLoggingException(e);
068        }
069    }
070
071    @Override
072    public void stop() {
073        this.manager.release();
074        super.stop();
075    }
076
077    @PluginBuilderFactory
078    public static Builder newBuilder() {
079        return new Builder();
080    }
081
082    public static class Builder implements org.apache.logging.log4j.core.util.Builder<JmsAppender> {
083
084        @PluginBuilderAttribute
085        @Required(message = "A name for the JmsAppender must be specified")
086        private String name;
087
088        @PluginBuilderAttribute
089        private String factoryName;
090
091        @PluginBuilderAttribute
092        private String providerUrl;
093
094        @PluginBuilderAttribute
095        private String urlPkgPrefixes;
096
097        @PluginBuilderAttribute
098        private String securityPrincipalName;
099
100        @PluginBuilderAttribute(sensitive = true)
101        private String securityCredentials;
102
103        @PluginBuilderAttribute
104        @Required(message = "A javax.jms.ConnectionFactory JNDI name must be specified")
105        private String factoryBindingName;
106
107        @PluginBuilderAttribute
108        @PluginAliases({"queueBindingName", "topicBindingName"})
109        @Required(message = "A javax.jms.Destination JNDI name must be specified")
110        private String destinationBindingName;
111
112        @PluginBuilderAttribute
113        private String username;
114
115        @PluginBuilderAttribute(sensitive = true)
116        private String password;
117
118        @PluginElement("Layout")
119        private Layout<? extends Serializable> layout = SerializedLayout.createLayout();
120
121        @PluginElement("Filter")
122        private Filter filter;
123
124        @PluginBuilderAttribute
125        private boolean ignoreExceptions = true;
126
127        private Builder() {
128        }
129
130        public Builder setName(final String name) {
131            this.name = name;
132            return this;
133        }
134
135        public Builder setFactoryName(final String factoryName) {
136            this.factoryName = factoryName;
137            return this;
138        }
139
140        public Builder setProviderUrl(final String providerUrl) {
141            this.providerUrl = providerUrl;
142            return this;
143        }
144
145        public Builder setUrlPkgPrefixes(final String urlPkgPrefixes) {
146            this.urlPkgPrefixes = urlPkgPrefixes;
147            return this;
148        }
149
150        public Builder setSecurityPrincipalName(final String securityPrincipalName) {
151            this.securityPrincipalName = securityPrincipalName;
152            return this;
153        }
154
155        public Builder setSecurityCredentials(final String securityCredentials) {
156            this.securityCredentials = securityCredentials;
157            return this;
158        }
159
160        public Builder setFactoryBindingName(final String factoryBindingName) {
161            this.factoryBindingName = factoryBindingName;
162            return this;
163        }
164
165        public Builder setDestinationBindingName(final String destinationBindingName) {
166            this.destinationBindingName = destinationBindingName;
167            return this;
168        }
169
170        public Builder setUsername(final String username) {
171            this.username = username;
172            return this;
173        }
174
175        public Builder setPassword(final String password) {
176            this.password = password;
177            return this;
178        }
179
180        public Builder setLayout(final Layout<? extends Serializable> layout) {
181            this.layout = layout;
182            return this;
183        }
184
185        public Builder setFilter(final Filter filter) {
186            this.filter = filter;
187            return this;
188        }
189
190        public Builder setIgnoreExceptions(final boolean ignoreExceptions) {
191            this.ignoreExceptions = ignoreExceptions;
192            return this;
193        }
194
195        @Override
196        public JmsAppender build() {
197            final JndiManager jndiManager = JndiManager.getJndiManager(factoryName, providerUrl, urlPkgPrefixes,
198                securityPrincipalName, securityCredentials, null);
199            final JmsManager jmsManager = JmsManager.getJmsManager(name, jndiManager, factoryBindingName,
200                destinationBindingName, username, password);
201            try {
202                return new JmsAppender(name, filter, layout, ignoreExceptions, jmsManager);
203            } catch (final JMSException e) {
204                LOGGER.error("Error creating JmsAppender [{}].", name, e);
205                return null;
206            }
207        }
208    }
209
210}