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.net; 019 020import java.util.Properties; 021import java.util.concurrent.TimeUnit; 022 023import javax.naming.Context; 024import javax.naming.InitialContext; 025import javax.naming.NamingException; 026 027import org.apache.logging.log4j.core.appender.AbstractManager; 028import org.apache.logging.log4j.core.appender.ManagerFactory; 029import org.apache.logging.log4j.core.util.JndiCloser; 030 031/** 032 * Manages a JNDI {@link javax.naming.Context}. 033 * 034 * @since 2.1 035 */ 036public class JndiManager extends AbstractManager { 037 038 private static final JndiManagerFactory FACTORY = new JndiManagerFactory(); 039 040 private final Context context; 041 042 private JndiManager(final String name, final Context context) { 043 super(null, name); 044 this.context = context; 045 } 046 047 /** 048 * Gets the default JndiManager using the default {@link javax.naming.InitialContext}. 049 * 050 * @return the default JndiManager 051 */ 052 public static JndiManager getDefaultManager() { 053 return getManager(JndiManager.class.getName(), FACTORY, null); 054 } 055 056 /** 057 * Gets a named JndiManager using the default {@link javax.naming.InitialContext}. 058 * 059 * @param name the name of the JndiManager instance to create or use if available 060 * @return a default JndiManager 061 */ 062 public static JndiManager getDefaultManager(final String name) { 063 return getManager(name, FACTORY, null); 064 } 065 066 /** 067 * Gets a JndiManager with the provided configuration information. 068 * 069 * @param initialContextFactoryName Fully qualified class name of an implementation of 070 * {@link javax.naming.spi.InitialContextFactory}. 071 * @param providerURL The provider URL to use for the JNDI connection (specific to the above factory). 072 * @param urlPkgPrefixes A colon-separated list of package prefixes for the class name of the factory 073 * class that will create a URL context factory 074 * @param securityPrincipal The name of the identity of the Principal. 075 * @param securityCredentials The security credentials of the Principal. 076 * @param additionalProperties Any additional JNDI environment properties to set or {@code null} for none. 077 * @return the JndiManager for the provided parameters. 078 */ 079 public static JndiManager getJndiManager(final String initialContextFactoryName, 080 final String providerURL, 081 final String urlPkgPrefixes, 082 final String securityPrincipal, 083 final String securityCredentials, 084 final Properties additionalProperties) { 085 final Properties properties = createProperties(initialContextFactoryName, providerURL, urlPkgPrefixes, 086 securityPrincipal, securityCredentials, additionalProperties); 087 return getManager(createManagerName(), FACTORY, properties); 088 } 089 090 /** 091 * Gets a JndiManager with the provided configuration information. 092 * 093 * @param properties JNDI properties, usually created by calling {@link #createProperties(String, String, String, String, String, Properties)}. 094 * @return the JndiManager for the provided parameters. 095 * @see #createProperties(String, String, String, String, String, Properties) 096 * @since 2.9 097 */ 098 public static JndiManager getJndiManager(final Properties properties) { 099 return getManager(createManagerName(), FACTORY, properties); 100 } 101 102 private static String createManagerName() { 103 return JndiManager.class.getName() + '@' + JndiManager.class.hashCode(); 104 } 105 106 /** 107 * Creates JNDI Properties with the provided configuration information. 108 * 109 * @param initialContextFactoryName 110 * Fully qualified class name of an implementation of {@link javax.naming.spi.InitialContextFactory}. 111 * @param providerURL 112 * The provider URL to use for the JNDI connection (specific to the above factory). 113 * @param urlPkgPrefixes 114 * A colon-separated list of package prefixes for the class name of the factory class that will create a 115 * URL context factory 116 * @param securityPrincipal 117 * The name of the identity of the Principal. 118 * @param securityCredentials 119 * The security credentials of the Principal. 120 * @param additionalProperties 121 * Any additional JNDI environment properties to set or {@code null} for none. 122 * @return the Properties for the provided parameters. 123 * @since 2.9 124 */ 125 public static Properties createProperties(final String initialContextFactoryName, final String providerURL, 126 final String urlPkgPrefixes, final String securityPrincipal, final String securityCredentials, 127 final Properties additionalProperties) { 128 if (initialContextFactoryName == null) { 129 return null; 130 } 131 final Properties properties = new Properties(); 132 properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName); 133 if (providerURL != null) { 134 properties.setProperty(Context.PROVIDER_URL, providerURL); 135 } else { 136 LOGGER.warn("The JNDI InitialContextFactory class name [{}] was provided, but there was no associated " 137 + "provider URL. This is likely to cause problems.", initialContextFactoryName); 138 } 139 if (urlPkgPrefixes != null) { 140 properties.setProperty(Context.URL_PKG_PREFIXES, urlPkgPrefixes); 141 } 142 if (securityPrincipal != null) { 143 properties.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal); 144 if (securityCredentials != null) { 145 properties.setProperty(Context.SECURITY_CREDENTIALS, securityCredentials); 146 } else { 147 LOGGER.warn("A security principal [{}] was provided, but with no corresponding security credentials.", 148 securityPrincipal); 149 } 150 } 151 if (additionalProperties != null) { 152 properties.putAll(additionalProperties); 153 } 154 return properties; 155 } 156 157 @Override 158 protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) { 159 return JndiCloser.closeSilently(this.context); 160 } 161 162 /** 163 * Looks up a named object through this JNDI context. 164 * 165 * @param name name of the object to look up. 166 * @param <T> the type of the object. 167 * @return the named object if it could be located. 168 * @throws NamingException if a naming exception is encountered 169 */ 170 @SuppressWarnings("unchecked") 171 public <T> T lookup(final String name) throws NamingException { 172 return (T) this.context.lookup(name); 173 } 174 175 private static class JndiManagerFactory implements ManagerFactory<JndiManager, Properties> { 176 177 @Override 178 public JndiManager createManager(final String name, final Properties data) { 179 try { 180 return new JndiManager(name, new InitialContext(data)); 181 } catch (final NamingException e) { 182 LOGGER.error("Error creating JNDI InitialContext.", e); 183 return null; 184 } 185 } 186 } 187 188 @Override 189 public String toString() { 190 return "JndiManager [context=" + context + ", count=" + count + "]"; 191 } 192 193}