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.config.plugins.processor; 019 020import java.io.BufferedInputStream; 021import java.io.BufferedOutputStream; 022import java.io.DataInputStream; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.io.OutputStream; 026import java.net.URL; 027import java.util.Enumeration; 028import java.util.LinkedHashMap; 029import java.util.Map; 030 031/** 032 * 033 */ 034public class PluginCache { 035 private final Map<String, Map<String, PluginEntry>> categories = 036 new LinkedHashMap<>(); 037 038 /** 039 * Returns all categories of plugins in this cache. 040 * 041 * @return all categories of plugins in this cache. 042 * @since 2.1 043 */ 044 public Map<String, Map<String, PluginEntry>> getAllCategories() { 045 return categories; 046 } 047 048 /** 049 * Gets or creates a category of plugins. 050 * 051 * @param category name of category to look up. 052 * @return plugin mapping of names to plugin entries. 053 */ 054 public Map<String, PluginEntry> getCategory(final String category) { 055 final String key = category.toLowerCase(); 056 if (!categories.containsKey(key)) { 057 categories.put(key, new LinkedHashMap<String, PluginEntry>()); 058 } 059 return categories.get(key); 060 } 061 062 /** 063 * Stores the plugin cache to a given OutputStream. 064 * 065 * @param os destination to save cache to. 066 * @throws IOException if an I/O exception occurs. 067 */ 068 // NOTE: if this file format is to be changed, the filename should change and this format should still be readable 069 public void writeCache(final OutputStream os) throws IOException { 070 try (final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(os))) { 071 // See PluginManager.readFromCacheFiles for the corresponding decoder. Format may not be changed 072 // without breaking existing Log4j2Plugins.dat files. 073 out.writeInt(categories.size()); 074 for (final Map.Entry<String, Map<String, PluginEntry>> category : categories.entrySet()) { 075 out.writeUTF(category.getKey()); 076 final Map<String, PluginEntry> m = category.getValue(); 077 out.writeInt(m.size()); 078 for (final Map.Entry<String, PluginEntry> entry : m.entrySet()) { 079 final PluginEntry plugin = entry.getValue(); 080 out.writeUTF(plugin.getKey()); 081 out.writeUTF(plugin.getClassName()); 082 out.writeUTF(plugin.getName()); 083 out.writeBoolean(plugin.isPrintable()); 084 out.writeBoolean(plugin.isDefer()); 085 } 086 } 087 } 088 } 089 090 /** 091 * Loads and merges all the Log4j plugin cache files specified. Usually, this is obtained via a ClassLoader. 092 * 093 * @param resources URLs to all the desired plugin cache files to load. 094 * @throws IOException if an I/O exception occurs. 095 */ 096 public void loadCacheFiles(final Enumeration<URL> resources) throws IOException { 097 categories.clear(); 098 while (resources.hasMoreElements()) { 099 final URL url = resources.nextElement(); 100 try (final DataInputStream in = new DataInputStream(new BufferedInputStream(url.openStream()))) { 101 final int count = in.readInt(); 102 for (int i = 0; i < count; i++) { 103 final String category = in.readUTF(); 104 final Map<String, PluginEntry> m = getCategory(category); 105 final int entries = in.readInt(); 106 for (int j = 0; j < entries; j++) { 107 final PluginEntry entry = new PluginEntry(); 108 entry.setKey(in.readUTF()); 109 entry.setClassName(in.readUTF()); 110 entry.setName(in.readUTF()); 111 entry.setPrintable(in.readBoolean()); 112 entry.setDefer(in.readBoolean()); 113 entry.setCategory(category); 114 if (!m.containsKey(entry.getKey())) { 115 m.put(entry.getKey(), entry); 116 } 117 } 118 } 119 } 120 } 121 } 122 123 /** 124 * Gets the number of plugin categories registered. 125 * 126 * @return number of plugin categories in cache. 127 */ 128 public int size() { 129 return categories.size(); 130 } 131}