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.config.plugins.util;
019    
020    import java.io.Serializable;
021    import java.util.Map;
022    import java.util.Set;
023    import java.util.concurrent.ConcurrentHashMap;
024    import java.util.concurrent.ConcurrentMap;
025    
026    /**
027     * Registry for PluginType maps partitioned by category names.
028     *
029     * @param <T> plugin information object such as PluginType or PluginEntry.
030     */
031    public class PluginRegistry<T extends Serializable> {
032        private final ConcurrentMap<String, ConcurrentMap<String, T>> categories =
033            new ConcurrentHashMap<String, ConcurrentMap<String, T>>();
034    
035        /**
036         * Gets or creates a plugin category if not already available. Category names are case-insensitive. The
037         * ConcurrentMap that is returned should also be treated as a case-insensitive plugin map where names should be
038         * converted to lowercase before retrieval or storage.
039         *
040         * @param category the plugin category to look up or create.
041         * @return the plugin map for the given category name.
042         * @throws IllegalArgumentException if the argument is {@code null}
043         */
044        public ConcurrentMap<String, T> getCategory(final String category) {
045            if (category == null) {
046                throw new IllegalArgumentException("Category name cannot be null.");
047            }
048            final String key = category.toLowerCase();
049            categories.putIfAbsent(key, new ConcurrentHashMap<String, T>());
050            return categories.get(key);
051        }
052    
053        /**
054         * Returns the number of plugin categories currently available. This is primarily useful for serialization.
055         *
056         * @return the number of plugin categories.
057         */
058        public int getCategoryCount() {
059            return categories.size();
060        }
061    
062        /**
063         * Indicates whether or not any plugin categories have been registered. Note that this does not necessarily
064         * indicate if any plugins are registered as categories may be empty.
065         *
066         * @return {@code true} if there any categories registered.
067         */
068        public boolean isEmpty() {
069            return categories.isEmpty();
070        }
071    
072        /**
073         * Resets the registry to an empty state.
074         */
075        public void clear() {
076            categories.clear();
077        }
078    
079        /**
080         * Indicates whether or not the given category name is registered and has plugins in that category.
081         *
082         * @param category the plugin category name to check.
083         * @return {@code true} if the category exists and has plugins registered.
084         * @throws IllegalArgumentException if the argument is {@code null}
085         */
086        public boolean hasCategory(final String category) {
087            if (category == null) {
088                throw new IllegalArgumentException("Category name cannot be null.");
089            }
090            final String key = category.toLowerCase();
091            return categories.containsKey(key) && !categories.get(key).isEmpty();
092        }
093    
094        /**
095         * Gets an entry set for iterating over the registered plugin categories.
096         *
097         * @return an entry set of the registered plugin categories.
098         */
099        public Set<Map.Entry<String, ConcurrentMap<String, T>>> getCategories() {
100            return categories.entrySet();
101        }
102    }