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