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.processor;
019    
020    import java.io.BufferedInputStream;
021    import java.io.BufferedOutputStream;
022    import java.io.DataInputStream;
023    import java.io.DataOutputStream;
024    import java.io.IOException;
025    import java.io.OutputStream;
026    import java.net.URL;
027    import java.util.Enumeration;
028    import java.util.Map;
029    import java.util.concurrent.ConcurrentMap;
030    
031    import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;
032    
033    /**
034     *
035     */
036    public class PluginCache {
037        private final transient PluginRegistry<PluginEntry> pluginCategories = new PluginRegistry<PluginEntry>();
038    
039        /**
040         * Gets or creates a category of plugins.
041         *
042         * @param category name of category to look up.
043         * @return plugin mapping of names to plugin entries.
044         */
045        public ConcurrentMap<String, PluginEntry> getCategory(final String category) {
046            return pluginCategories.getCategory(category);
047        }
048    
049        /**
050         * Stores the plugin cache to a given OutputStream.
051         *
052         * @param os destination to save cache to.
053         * @throws IOException
054         */
055        public void writeCache(final OutputStream os) throws IOException {
056            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(os));
057            try {
058                out.writeInt(pluginCategories.getCategoryCount());
059                for (final Map.Entry<String, ConcurrentMap<String, PluginEntry>> category : pluginCategories.getCategories()) {
060                    out.writeUTF(category.getKey());
061                    final Map<String, PluginEntry> m = category.getValue();
062                    out.writeInt(m.size());
063                    for (final Map.Entry<String, PluginEntry> entry : m.entrySet()) {
064                        final PluginEntry plugin = entry.getValue();
065                        out.writeUTF(plugin.getKey());
066                        out.writeUTF(plugin.getClassName());
067                        out.writeUTF(plugin.getName());
068                        out.writeBoolean(plugin.isPrintable());
069                        out.writeBoolean(plugin.isDefer());
070                    }
071                }
072            } finally {
073                out.close();
074            }
075        }
076    
077        /**
078         * Loads and merges all the Log4j plugin cache files specified. Usually, this is obtained via a ClassLoader.
079         *
080         * @param resources URLs to all the desired plugin cache files to load.
081         * @throws IOException
082         */
083        public void loadCacheFiles(final Enumeration<URL> resources) throws IOException {
084            pluginCategories.clear();
085            while (resources.hasMoreElements()) {
086                final URL url = resources.nextElement();
087                final DataInputStream in = new DataInputStream(new BufferedInputStream(url.openStream()));
088                try {
089                    final int count = in.readInt();
090                    for (int i = 0; i < count; i++) {
091                        final String category = in.readUTF();
092                        final ConcurrentMap<String, PluginEntry> m = pluginCategories.getCategory(category);
093                        final int entries = in.readInt();
094                        for (int j = 0; j < entries; j++) {
095                            final PluginEntry entry = new PluginEntry();
096                            entry.setKey(in.readUTF());
097                            entry.setClassName(in.readUTF());
098                            entry.setName(in.readUTF());
099                            entry.setPrintable(in.readBoolean());
100                            entry.setDefer(in.readBoolean());
101                            entry.setCategory(category);
102                            m.putIfAbsent(entry.getKey(), entry);
103                        }
104                    }
105                } finally {
106                    in.close();
107                }
108            }
109        }
110    
111        /**
112         * Gets the number of plugin categories registered.
113         *
114         * @return number of plugin categories in cache.
115         */
116        public int size() {
117            return pluginCategories.getCategoryCount();
118        }
119    }