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