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 org.apache.logging.log4j.core.util.Closer;
21  
22  import java.io.BufferedInputStream;
23  import java.io.BufferedOutputStream;
24  import java.io.DataInputStream;
25  import java.io.DataOutputStream;
26  import java.io.IOException;
27  import java.io.OutputStream;
28  import java.net.URL;
29  import java.util.Enumeration;
30  import java.util.LinkedHashMap;
31  import java.util.Map;
32  
33  /**
34   *
35   */
36  public class PluginCache {
37      private final Map<String, Map<String, PluginEntry>> categories =
38          new LinkedHashMap<String, Map<String, PluginEntry>>();
39  
40      /**
41       * Returns all categories of plugins in this cache.
42       *
43       * @return all categories of plugins in this cache.
44       * @since 2.1
45       */
46      public Map<String, Map<String, PluginEntry>> getAllCategories() {
47          return categories;
48      }
49  
50      /**
51       * Gets or creates a category of plugins.
52       *
53       * @param category name of category to look up.
54       * @return plugin mapping of names to plugin entries.
55       */
56      public Map<String, PluginEntry> getCategory(final String category) {
57          final String key = category.toLowerCase();
58          if (!categories.containsKey(key)) {
59              categories.put(key, new LinkedHashMap<String, PluginEntry>());
60          }
61          return categories.get(key);
62      }
63  
64      /**
65       * Stores the plugin cache to a given OutputStream.
66       *
67       * @param os destination to save cache to.
68       * @throws IOException
69       */
70      // NOTE: if this file format is to be changed, the filename should change and this format should still be readable
71      public void writeCache(final OutputStream os) throws IOException {
72          final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(os));
73          try {
74              // See PluginManager.readFromCacheFiles for the corresponding decoder. Format may not be changed
75              // without breaking existing Log4j2Plugins.dat files.
76              out.writeInt(categories.size());
77              for (final Map.Entry<String, Map<String, PluginEntry>> category : categories.entrySet()) {
78                  out.writeUTF(category.getKey());
79                  final Map<String, PluginEntry> m = category.getValue();
80                  out.writeInt(m.size());
81                  for (final Map.Entry<String, PluginEntry> entry : m.entrySet()) {
82                      final PluginEntry plugin = entry.getValue();
83                      out.writeUTF(plugin.getKey());
84                      out.writeUTF(plugin.getClassName());
85                      out.writeUTF(plugin.getName());
86                      out.writeBoolean(plugin.isPrintable());
87                      out.writeBoolean(plugin.isDefer());
88                  }
89              }
90          } finally {
91              Closer.closeSilently(out);
92          }
93      }
94  
95      /**
96       * Loads and merges all the Log4j plugin cache files specified. Usually, this is obtained via a ClassLoader.
97       *
98       * @param resources URLs to all the desired plugin cache files to load.
99       * @throws IOException
100      */
101     public void loadCacheFiles(final Enumeration<URL> resources) throws IOException {
102         categories.clear();
103         while (resources.hasMoreElements()) {
104             final URL url = resources.nextElement();
105             final DataInputStream in = new DataInputStream(new BufferedInputStream(url.openStream()));
106             try {
107                 final int count = in.readInt();
108                 for (int i = 0; i < count; i++) {
109                     final String category = in.readUTF();
110                     final Map<String, PluginEntry> m = getCategory(category);
111                     final int entries = in.readInt();
112                     for (int j = 0; j < entries; j++) {
113                         final PluginEntry entry = new PluginEntry();
114                         entry.setKey(in.readUTF());
115                         entry.setClassName(in.readUTF());
116                         entry.setName(in.readUTF());
117                         entry.setPrintable(in.readBoolean());
118                         entry.setDefer(in.readBoolean());
119                         entry.setCategory(category);
120                         if (!m.containsKey(entry.getKey())) {
121                             m.put(entry.getKey(), entry);
122                         }
123                     }
124                 }
125             } finally {
126                 Closer.closeSilently(in);
127             }
128         }
129     }
130 
131     /**
132      * Gets the number of plugin categories registered.
133      *
134      * @return number of plugin categories in cache.
135      */
136     public int size() {
137         return categories.size();
138     }
139 }