/*
 * JMSTopicTargetFactory.java
 *
 * Created on August 26, 2001, 5:17 PM
 */

package org.apache.avalon.excalibur.logger.factory;

import org.apache.avalon.excalibur.logger.LogTargetFactory;

import org.apache.log.LogTarget;
import org.apache.log.output.jms.JMSTopicTarget;
import org.apache.log.output.jms.JMSQueueTarget;
import org.apache.log.output.jms.MessageBuilder;
import org.apache.log.output.jms.ObjectMessageBuilder;
import org.apache.log.output.jms.TextMessageBuilder;
import org.apache.log.output.jms.FormattedTextMessageBuilder;
import org.apache.log.format.Formatter;
import org.apache.log.output.jms.ContentInfo;
import org.apache.log.output.jms.PropertyInfo;
import org.apache.log.output.jms.PropertyType;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.ConfigurationException;

import javax.jms.ConnectionFactory;
import javax.jms.TopicConnectionFactory;
import javax.jms.QueueConnectionFactory;
import javax.jms.Destination;
import javax.jms.Topic;
import javax.jms.Queue;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;


/**
 * Factory for JMS LogTarget-s. The configuration looks like this:
 *
 * <pre>
 *   <jms id="name">
 *           <connection-factory>java:/TopicConectionFactory</connection-factory>
 *           <destination type="topic|queue">jms/LogTopic</destination>
 *           <message type="object|text|formatted-text|xml">
 *
 * -if type="formatted-text|xml":
 *                   <format type="exteded">%7.7{priority} %5.5{time}   [%8.8{category}] (%{context}): %{message}\n%{throwable}</format>
 * -if type="text":
 *                   <property>
 *                           <category>CATEGORY</category>
 *                           <priority>PRIORITY</priority>
 *                           <time>TIME</time>
 *                           <rtime>RTIME</rtime>
 *                           <throwable>THROWABLE</throwable>
 *                           <hostname>HOSTNAME</hostname>
 *                           <static aux="234523454325">SYSTEM</static>
 *                           <context aux="principal">PRINCIPAL</context>
 *                           <context aux="ipaddress">IPADDRESS</context>
 *                           <context aux="username">USERNAME</context>
 *                   </property>
 *                   <content>
 *                           <message/>
 *                   </content>
 *           </message>
 *   </jms>
 * </pre>
 *
 * @author <a href="mailto:mirceatoma@home.com">Mircea Toma</a>;
 * @version CVS $Revision$ $Date$
 */
public class JMSTargetFactory implements LogTargetFactory
{
    
    public LogTarget createTarget( final Configuration configuration )
    throws ConfigurationException
    {
        final String factoryName =
            configuration.getChild( "connection-factory", true ).getValue();
        
        final Configuration destinationConf =
            configuration.getChild( "destination", true );
        
        final String destinationName = destinationConf.getValue();
        final String destinationType =
            destinationConf.getAttribute( "type", "topic" );
        
        final Configuration messageConf =
            configuration.getChild( "message", true );
        
        final MessageBuilder messageBuilder = getMessageBuilder( messageConf );
        final ConnectionFactory factory;
        final Destination destination;
        final LogTarget logTarget;
        
        try
        {
            Context ctx = new InitialContext();
            factory = (ConnectionFactory) ctx.lookup( factoryName );
            destination = (Destination) ctx.lookup( destinationName );
        }
        catch ( NameNotFoundException nnfe )
        {
            throw new ConfigurationException( "Cannot lookup object", nnfe );
        }
        catch ( NamingException ne )
        {
            throw new ConfigurationException( "Cannot get naming context", ne );
        }
        
        if ( "queue".equals( destinationType ) )
        {
            logTarget = new JMSQueueTarget( messageBuilder,
                    (QueueConnectionFactory) factory, (Queue) destination );
        }
        else
        {
            logTarget = new JMSTopicTarget( messageBuilder,
                (TopicConnectionFactory) factory, (Topic) destination );
        }
        
        return logTarget;
    }
    
    private MessageBuilder getMessageBuilder( final Configuration configuration )
    throws ConfigurationException
    {
        final String messageType = configuration.getAttribute( "type", "object" );
        
        if ( "text".equals( messageType ) )
        {
            final Configuration[] propertyConf =
                configuration.getChild( "property", true ).getChildren();
            final Configuration contentConf = configuration.getChild( "content", true );

            final PropertyInfo[] properties = new PropertyInfo[propertyConf.length];
            final ContentInfo content;

            for (int i = 0; i < properties.length; i++)
            {
                final String name = propertyConf[i].getValue();
                final int type = PropertyType.getTypeIdFor( propertyConf[i].getName() );
                final String aux = propertyConf[i].getAttribute( "aux", null );

                properties[i] = new PropertyInfo(name, type, aux);
            }

            final int type = PropertyType.getTypeIdFor( contentConf.getName() );
            final String aux = contentConf.getAttribute( "aux", null );
            content = new ContentInfo( type, aux);

            return new TextMessageBuilder( properties, content );
        }
        
        if ( "formatted-text".equals( messageType ) )
        {
            final Configuration conf = configuration.getChild( "format" );
            final FormatterFactory formatterFactory = new FormatterFactory();
            final Formatter formatter = formatterFactory.createFormatter( conf );
            
            return new FormattedTextMessageBuilder( formatter );
        }
        
        return new ObjectMessageBuilder();        
    }
}
