    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    }