1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
239
240 private enum ErrorType {
241 CLASS_NOT_FOUND
242 }
243
244
245
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 }