/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.log4j.net; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /** * A simple appender that publishes events to a JMS Topic. The events * are serialized and transmitted as JMS message type {@link * ObjectMessage}. * <p>JMS {@link Topic topics} and {@link TopicConnectionFactory topic * connection factories} are administered objects that are retrieved * using JNDI messaging which in turn requires the retreival of a JNDI * {@link Context}. * <p>There are two common methods for retrieving a JNDI {@link * Context}. If a file resource named <em>jndi.properties</em> is * available to the JNDI API, it will use the information found * therein to retrieve an initial JNDI context. To obtain an initial * context, your code will simply call: <pre> InitialContext jndiContext = new InitialContext(); </pre> * <p>Calling the no-argument <code>InitialContext()</code> method * will also work from within Enterprise Java Beans (EJBs) because it * is part of the EJB contract for application servers to provide each * bean an environment naming context (ENC). * <p>In the second approach, several predetermined properties are set * and these properties are passed to the <code>InitialContext</code> * contructor to connect to the naming service provider. For example, * to connect to JBoss naming service one would write: <pre> Properties env = new Properties( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); env.put(Context.PROVIDER_URL, "jnp://hostname:1099"); env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); InitialContext jndiContext = new InitialContext(env); </pre> * where <em>hostname</em> is the host where the JBoss applicaiton * server is running. * * <p>To connect to the the naming service of Weblogic application * server one would write: <pre> Properties env = new Properties( ); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL, "t3://localhost:7001"); InitialContext jndiContext = new InitialContext(env); </pre> * <p>Other JMS providers will obviously require different values. * * The initial JNDI context can be obtained by calling the * no-argument <code>InitialContext()</code> method in EJBs. Only * clients running in a separate JVM need to be concerned about the * <em>jndi.properties</em> file and calling {@link * InitialContext#InitialContext()} or alternatively correctly * setting the different properties before calling {@link * InitialContext#InitialContext(java.util.Hashtable)} method. @author Ceki Gülcü */ public class JMSAppender extends AppenderSkeleton { String securityPrincipalName; String securityCredentials; String initialContextFactoryName; String urlPkgPrefixes; String providerURL; String topicBindingName; String tcfBindingName; String userName; String password; boolean locationInfo; public JMSAppender() { } /** The <b>TopicConnectionFactoryBindingName</b> option takes a string value. Its value will be used to lookup the appropriate <code>TopicConnectionFactory</code> from the JNDI context. */ public void setTopicConnectionFactoryBindingName(String tcfBindingName) { this.tcfBindingName = tcfBindingName; } /** Returns the value of the <b>TopicConnectionFactoryBindingName</b> option. */ public String getTopicConnectionFactoryBindingName() { return tcfBindingName; } /** The <b>TopicBindingName</b> option takes a string value. Its value will be used to lookup the appropriate <code>Topic</code> from the JNDI context. */ public void setTopicBindingName(String topicBindingName) { this.topicBindingName = topicBindingName; } /** Returns the value of the <b>TopicBindingName</b> option. */ public String getTopicBindingName() { return topicBindingName; } /** Returns value of the <b>LocationInfo</b> property which determines whether location (stack) info is sent to the remote subscriber. */ public boolean getLocationInfo() { return locationInfo; } /** * Options are activated and become effective only after calling * this method.*/ public void activateOptions() { throw new UnsupportedOperationException(); } protected Object lookup(Context ctx, String name) throws NamingException { try { return ctx.lookup(name); } catch(NameNotFoundException e) { LogLog.error("Could not find name ["+name+"]."); throw e; } } protected boolean checkEntryConditions() { throw new UnsupportedOperationException(); } /** Close this JMSAppender. Closing releases all resources used by the appender. A closed appender cannot be re-opened. */ public synchronized void close() { throw new UnsupportedOperationException(); } /** This method called by {@link AppenderSkeleton#doAppend} method to do most of the real appending work. */ public void append(LoggingEvent event) { throw new UnsupportedOperationException(); } /** * Returns the value of the <b>InitialContextFactoryName</b> option. * See {@link #setInitialContextFactoryName} for more details on the * meaning of this option. * */ public String getInitialContextFactoryName() { return initialContextFactoryName; } /** * Setting the <b>InitialContextFactoryName</b> method will cause * this <code>JMSAppender</code> instance to use the {@link * InitialContext#InitialContext(Hashtable)} method instead of the * no-argument constructor. If you set this option, you should also * at least set the <b>ProviderURL</b> option. * * <p>See also {@link #setProviderURL(String)}. * */ public void setInitialContextFactoryName(String initialContextFactoryName) { this.initialContextFactoryName = initialContextFactoryName; } public String getProviderURL() { return providerURL; } public void setProviderURL(String providerURL) { this.providerURL = providerURL; } String getURLPkgPrefixes( ) { return urlPkgPrefixes; } public void setURLPkgPrefixes(String urlPkgPrefixes ) { this.urlPkgPrefixes = urlPkgPrefixes; } public String getSecurityCredentials() { return securityCredentials; } public void setSecurityCredentials(String securityCredentials) { this.securityCredentials = securityCredentials; } public String getSecurityPrincipalName() { return securityPrincipalName; } public void setSecurityPrincipalName(String securityPrincipalName) { this.securityPrincipalName = securityPrincipalName; } public String getUserName() { return userName; } /** * The user name to use when {@link * TopicConnectionFactory#createTopicConnection(String, String) * creating a topic session}. If you set this option, you should * also set the <b>Password</b> option. See {@link * #setPassword(String)}. * */ public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } /** * The paswword to use when creating a topic session. */ public void setPassword(String password) { this.password = password; } /** If true, the information sent to the remote subscriber will include caller's location information. By default no location information is sent to the subscriber. */ public void setLocationInfo(boolean locationInfo) { this.locationInfo = locationInfo; } /** * Returns the TopicConnection used for this appender. Only valid after * activateOptions() method has been invoked. */ protected Object getTopicConnection() { throw new UnsupportedOperationException(); } /** * Returns the TopicSession used for this appender. Only valid after * activateOptions() method has been invoked. */ protected Object getTopicSession() { throw new UnsupportedOperationException(); } /** * Returns the TopicPublisher used for this appender. Only valid after * activateOptions() method has been invoked. */ protected Object getTopicPublisher() { throw new UnsupportedOperationException(); } /** * The JMSAppender sends serialized events and consequently does not * require a layout. */ public boolean requiresLayout() { return false; } }