View Javadoc
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 }