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  package org.apache.logging.log4j.core.config;
18  
19  import org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.core.config.plugins.PluginManager;
21  import org.apache.logging.log4j.core.config.plugins.PluginType;
22  import org.apache.logging.log4j.core.config.plugins.ResolverUtil;
23  import org.apache.logging.log4j.status.StatusConsoleListener;
24  import org.apache.logging.log4j.status.StatusListener;
25  import org.apache.logging.log4j.status.StatusLogger;
26  import org.codehaus.jackson.JsonNode;
27  import org.codehaus.jackson.JsonParser;
28  import org.codehaus.jackson.map.ObjectMapper;
29  import org.xml.sax.InputSource;
30  
31  import java.io.ByteArrayInputStream;
32  import java.io.ByteArrayOutputStream;
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.util.ArrayList;
37  import java.util.Iterator;
38  import java.util.List;
39  import java.util.Map;
40  
41  /**
42   * Creates a Node hierarchy from a JSON file.
43   */
44  public class JSONConfiguration extends BaseConfiguration {
45  
46      private static final String[] VERBOSE_CLASSES = new String[] {ResolverUtil.class.getName()};
47  
48      private static final int BUF_SIZE = 16384;
49  
50      private List<Status> status = new ArrayList<Status>();
51  
52      private JsonNode root;
53  
54      public JSONConfiguration(InputSource source, File configFile) {
55          byte[] buffer;
56  
57          try {
58              buffer = toByteArray(source.getByteStream());
59              InputStream is = new ByteArrayInputStream(buffer);
60              source = new InputSource(is);
61              ObjectMapper mapper = new ObjectMapper().configure(JsonParser.Feature.ALLOW_COMMENTS, true);
62              root = mapper.readTree(is);
63              if (root.size() == 1) {
64                  Iterator<JsonNode> i = root.getElements();
65                  root = i.next();
66              }
67              processAttributes(rootNode, root);
68              Level status = Level.OFF;
69              boolean verbose = false;
70              for (Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
71                  if ("status".equalsIgnoreCase(entry.getKey())) {
72                      status = Level.toLevel(entry.getValue().toUpperCase(), Level.OFF);
73                  } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
74                      verbose = Boolean.parseBoolean(entry.getValue());
75                  } else if ("packages".equalsIgnoreCase(entry.getKey())) {
76                      String[] packages = entry.getValue().split(",");
77                      for (String p : packages) {
78                          PluginManager.addPackage(p);
79                      }
80                  } else if ("name".equalsIgnoreCase(entry.getKey())) {
81                      setName(entry.getValue());
82                  } else if ("monitorInterval".equalsIgnoreCase(entry.getKey())) {
83                      int interval = Integer.parseInt(entry.getValue());
84                      if (interval > 0 && configFile != null) {
85                          monitor = new FileConfigurationMonitor(configFile, listeners, interval);
86                      }
87                  }
88              }
89  
90              Iterator<StatusListener> statusIter = ((StatusLogger) LOGGER).getListeners();
91              boolean found = false;
92              while (statusIter.hasNext()) {
93                  StatusListener listener = statusIter.next();
94                  if (listener instanceof StatusConsoleListener) {
95                      found = true;
96                      ((StatusConsoleListener) listener).setLevel(status);
97                      if (!verbose) {
98                          ((StatusConsoleListener) listener).setFilters(VERBOSE_CLASSES);
99                      }
100                 }
101             }
102             if (!found && status != Level.OFF) {
103                 StatusConsoleListener listener = new StatusConsoleListener(status);
104                 if (!verbose) {
105                     listener.setFilters(VERBOSE_CLASSES);
106                 }
107                 ((StatusLogger) LOGGER).registerListener(listener);
108             }
109             if (getName() == null) {
110                 setName(source.getSystemId());
111             }
112         } catch (Exception ex) {
113             LOGGER.error("Error parsing " + source.getSystemId(), ex);
114             ex.printStackTrace();
115         }
116     }
117 
118      public void setup() {
119         Iterator<Map.Entry<String, JsonNode>> iter = root.getFields();
120         List<Node> children = rootNode.getChildren();
121         while (iter.hasNext()) {
122             Map.Entry<String, JsonNode> entry = iter.next();
123             JsonNode n = entry.getValue();
124             if (n.isObject()) {
125                 LOGGER.debug("Processing node for object " + entry.getKey());
126                 children.add(constructNode(entry.getKey(), rootNode, n));
127             } else if (n.isArray()) {
128                 LOGGER.error("Arrays are not supported at the root configuration.");
129             }
130         }
131         LOGGER.debug("Completed parsing configuration");
132         if (status.size() > 0) {
133             for (Status s : status) {
134                 LOGGER.error("Error processing element " + s.name + ": " + s.errorType);
135             }
136             return;
137         }
138     }
139 
140     private Node constructNode(String name, Node parent, JsonNode jsonNode) {
141         PluginType type = getPluginManager().getPluginType(name);
142         Node node = new Node(parent, name, type);
143         processAttributes(node, jsonNode);
144         Iterator<Map.Entry<String, JsonNode>> iter = jsonNode.getFields();
145         List<Node> children = node.getChildren();
146         while (iter.hasNext()) {
147             Map.Entry<String, JsonNode> entry = iter.next();
148             JsonNode n = entry.getValue();
149             if (n.isArray() || n.isObject()) {
150                 if (type == null) {
151                     status.add(new Status(name, n, ErrorType.CLASS_NOT_FOUND));
152                 }
153                 if (n.isArray()) {
154                     LOGGER.debug("Processing node for array " + entry.getKey());
155                     for (int i = 0; i < n.size(); ++i) {
156                         String pluginType = getType(n.get(i), entry.getKey());
157                         PluginType entryType = getPluginManager().getPluginType(pluginType);
158                         Node item = new Node(node, entry.getKey(), entryType);
159                         processAttributes(item, n.get(i));
160                         if (pluginType.equals(entry.getKey())) {
161                             LOGGER.debug("Processing " + entry.getKey() + "[" + i + "]");
162                         } else {
163                             LOGGER.debug("Processing " + pluginType + " " + entry.getKey() + "[" + i + "]");
164                         }
165                         Iterator<Map.Entry<String, JsonNode>> itemIter = n.get(i).getFields();
166                         List<Node> itemChildren = item.getChildren();
167                         while (itemIter.hasNext()) {
168                             Map.Entry<String, JsonNode> itemEntry = itemIter.next();
169                             if (itemEntry.getValue().isObject()) {
170                                 LOGGER.debug("Processing node for object " + itemEntry.getKey());
171                                 itemChildren.add(constructNode(itemEntry.getKey(), item, itemEntry.getValue()));
172                             }
173                         }
174                         children.add(item);
175                     }
176                 } else {
177                     LOGGER.debug("Processing node for object " + entry.getKey());
178                     children.add(constructNode(entry.getKey(), node, n));
179                 }
180             }
181         }
182 
183         String t;
184         if (type == null) {
185             t = "null";
186         } else {
187             t = type.getElementName() + ":" + type.getPluginClass();
188         }
189 
190         String p = node.getParent() == null ? "null" : node.getParent().getName() == null ?
191             "root" : node.getParent().getName();
192         LOGGER.debug("Returning " + node.getName() + " with parent " + p + " of type " +  t);
193         return node;
194     }
195 
196     private String getType(JsonNode node, String name) {
197         Iterator<Map.Entry<String, JsonNode>> iter = node.getFields();
198         while (iter.hasNext()) {
199             Map.Entry<String, JsonNode> entry = iter.next();
200             if (entry.getKey().equalsIgnoreCase("type")) {
201                 JsonNode n = entry.getValue();
202                 if (n.isValueNode()) {
203                     return n.asText();
204                 }
205             }
206         }
207         return name;
208     }
209 
210     private void processAttributes(Node parent, JsonNode node) {
211         Map<String, String> attrs = parent.getAttributes();
212         Iterator<Map.Entry<String, JsonNode>> iter = node.getFields();
213         while (iter.hasNext()) {
214             Map.Entry<String, JsonNode> entry = iter.next();
215             if (!entry.getKey().equalsIgnoreCase("type")) {
216                 JsonNode n = entry.getValue();
217                 if (n.isValueNode()) {
218                     attrs.put(entry.getKey(), n.asText());
219                 }
220             }
221         }
222     }
223 
224     protected byte[] toByteArray(InputStream is) throws IOException {
225         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
226 
227         int nRead;
228         byte[] data = new byte[BUF_SIZE];
229 
230         while ((nRead = is.read(data, 0, data.length)) != -1) {
231             buffer.write(data, 0, nRead);
232         }
233 
234         return buffer.toByteArray();
235     }
236 
237     /**
238      * The error that occurred.
239      */
240     private enum ErrorType {
241         CLASS_NOT_FOUND
242     }
243 
244     /**
245      * Status for recording errors.
246      */
247     private class Status {
248         private JsonNode node;
249         private String name;
250         private ErrorType errorType;
251 
252         public Status(String name, JsonNode node, ErrorType errorType) {
253             this.name = name;
254             this.node = node;
255             this.errorType = errorType;
256         }
257     }
258 }