1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
16 */
17
18 package org.apache.logging.log4j.core.config.plugins.processor;
19
20 import java.io.BufferedInputStream;
21 import java.io.BufferedOutputStream;
22 import java.io.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.net.URL;
27 import java.util.Enumeration;
28 import java.util.LinkedHashMap;
29 import java.util.Map;
30
31 /**
32 *
33 */
34 public class PluginCache {
35 private final Map<String, Map<String, PluginEntry>> categories =
36 new LinkedHashMap<>();
37
38 /**
39 * Returns all categories of plugins in this cache.
40 *
41 * @return all categories of plugins in this cache.
42 * @since 2.1
43 */
44 public Map<String, Map<String, PluginEntry>> getAllCategories() {
45 return categories;
46 }
47
48 /**
49 * Gets or creates a category of plugins.
50 *
51 * @param category name of category to look up.
52 * @return plugin mapping of names to plugin entries.
53 */
54 public Map<String, PluginEntry> getCategory(final String category) {
55 final String key = category.toLowerCase();
56 if (!categories.containsKey(key)) {
57 categories.put(key, new LinkedHashMap<String, PluginEntry>());
58 }
59 return categories.get(key);
60 }
61
62 /**
63 * Stores the plugin cache to a given OutputStream.
64 *
65 * @param os destination to save cache to.
66 * @throws IOException if an I/O exception occurs.
67 */
68 // NOTE: if this file format is to be changed, the filename should change and this format should still be readable
69 public void writeCache(final OutputStream os) throws IOException {
70 try (final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(os))) {
71 // See PluginManager.readFromCacheFiles for the corresponding decoder. Format may not be changed
72 // without breaking existing Log4j2Plugins.dat files.
73 out.writeInt(categories.size());
74 for (final Map.Entry<String, Map<String, PluginEntry>> category : categories.entrySet()) {
75 out.writeUTF(category.getKey());
76 final Map<String, PluginEntry> m = category.getValue();
77 out.writeInt(m.size());
78 for (final Map.Entry<String, PluginEntry> entry : m.entrySet()) {
79 final PluginEntry plugin = entry.getValue();
80 out.writeUTF(plugin.getKey());
81 out.writeUTF(plugin.getClassName());
82 out.writeUTF(plugin.getName());
83 out.writeBoolean(plugin.isPrintable());
84 out.writeBoolean(plugin.isDefer());
85 }
86 }
87 }
88 }
89
90 /**
91 * Loads and merges all the Log4j plugin cache files specified. Usually, this is obtained via a ClassLoader.
92 *
93 * @param resources URLs to all the desired plugin cache files to load.
94 * @throws IOException if an I/O exception occurs.
95 */
96 public void loadCacheFiles(final Enumeration<URL> resources) throws IOException {
97 categories.clear();
98 while (resources.hasMoreElements()) {
99 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 }