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