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 */
017package org.apache.activemq.util;
018
019import org.apache.logging.log4j.core.Filter;
020import org.apache.logging.log4j.core.Layout;
021import org.apache.logging.log4j.core.LogEvent;
022import org.apache.logging.log4j.core.appender.AbstractAppender;
023
024import java.io.Serializable;
025import java.util.ArrayList;
026import java.util.Iterator;
027import java.util.List;
028import javax.jms.Connection;
029import javax.jms.Destination;
030import javax.jms.JMSException;
031import javax.jms.Message;
032import javax.jms.MessageProducer;
033import javax.jms.Session;
034import javax.naming.NamingException;
035
036
037/**
038 * An abstract base class for implementation inheritence for a log4j JMS
039 * appender
040 */
041public abstract class JmsLogAppenderSupport extends AbstractAppender {
042
043    private Connection connection;
044    private Session session;
045    private MessageProducer producer;
046    private boolean allowTextMessages = true;
047    private String subjectPrefix = "log4j.";
048
049    public JmsLogAppenderSupport() {
050        this("jmslog", (Filter) null);
051    }
052
053    protected JmsLogAppenderSupport(String name, Filter filter) {
054        super(name, filter, (Layout) null, true);
055    }
056
057    public Connection getConnection() throws JMSException, NamingException {
058        if (connection == null) {
059            connection = createConnection();
060        }
061        return connection;
062    }
063
064    public void setConnection(Connection connection) {
065        this.connection = connection;
066    }
067
068    public Session getSession() throws JMSException, NamingException {
069        if (session == null) {
070            session = createSession();
071        }
072        return session;
073    }
074
075    public void setSession(Session session) {
076        this.session = session;
077    }
078
079    public MessageProducer getProducer() throws JMSException, NamingException {
080        if (producer == null) {
081            producer = createProducer();
082        }
083        return producer;
084    }
085
086    public void setProducer(MessageProducer producer) {
087        this.producer = producer;
088    }
089
090    public void close() {
091        List<JMSException> errors = new ArrayList<JMSException>();
092        if (producer != null) {
093            try {
094                producer.close();
095            } catch (JMSException e) {
096                errors.add(e);
097            }
098        }
099        if (session != null) {
100            try {
101                session.close();
102            } catch (JMSException e) {
103                errors.add(e);
104            }
105        }
106        if (connection != null) {
107            try {
108                connection.close();
109            } catch (JMSException e) {
110                errors.add(e);
111            }
112        }
113        for (Iterator<JMSException> iter = errors.iterator(); iter.hasNext();) {
114            JMSException e = iter.next();
115            getHandler().error("Error closing JMS resources: " + e, e);
116        }
117    }
118
119    public boolean requiresLayout() {
120        return false;
121    }
122
123    public void activateOptions() {
124        try {
125            // lets ensure we're all created
126            getProducer();
127        } catch (Exception e) {
128            getHandler().error("Could not create JMS resources: " + e, e);
129        }
130    }
131
132    // Implementation methods
133    // -------------------------------------------------------------------------
134    protected abstract Connection createConnection() throws JMSException, NamingException;
135
136    protected Session createSession() throws JMSException, NamingException {
137        return getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE);
138    }
139
140    protected MessageProducer createProducer() throws JMSException, NamingException {
141        return getSession().createProducer(null);
142    }
143
144    private static final ThreadLocal<Object> APPENDING = new ThreadLocal<Object>();
145
146    public void append(LogEvent event) {
147        if( APPENDING.get()==null ) {
148            APPENDING.set(true);
149            try {
150                Message message = createMessage(event);
151                Destination destination = getDestination(event);
152                getProducer().send(destination, message);
153            } catch (Exception e) {
154                getHandler().error("Could not send message due to: " + e, event, e);
155            } finally {
156                APPENDING.remove();
157            }
158        }
159    }
160
161    protected Message createMessage(LogEvent event) throws JMSException, NamingException {
162        Message answer = null;
163        Object value = event.getMessage();
164        if (allowTextMessages && value instanceof String) {
165            answer = getSession().createTextMessage((String)value);
166        } else {
167            answer = getSession().createObjectMessage((Serializable)value);
168        }
169        answer.setStringProperty("level", event.getLevel().toString());
170        answer.setIntProperty("levelInt", event.getLevel().intLevel());
171        answer.setStringProperty("threadName", event.getThreadName());
172        return answer;
173    }
174
175    protected Destination getDestination(LogEvent event) throws JMSException, NamingException {
176        String name = subjectPrefix + event.getLoggerName();
177        return getSession().createTopic(name);
178    }
179}