1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.jmx;
18
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.PrintWriter;
27 import java.io.Reader;
28 import java.io.StringWriter;
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.util.Map;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import javax.management.MBeanNotificationInfo;
36 import javax.management.Notification;
37 import javax.management.NotificationBroadcasterSupport;
38 import javax.management.ObjectName;
39
40 import org.apache.logging.log4j.core.LoggerContext;
41 import org.apache.logging.log4j.core.config.Configuration;
42 import org.apache.logging.log4j.core.config.ConfigurationFactory;
43 import org.apache.logging.log4j.core.config.ConfigurationFactory.ConfigurationSource;
44 import org.apache.logging.log4j.core.helpers.Assert;
45 import org.apache.logging.log4j.status.StatusLogger;
46
47
48
49
50 public class LoggerContextAdmin extends NotificationBroadcasterSupport
51 implements LoggerContextAdminMBean, PropertyChangeListener {
52 private static final int PAGE = 4 * 1024;
53 private static final int TEXT_BUFFER = 64 * 1024;
54 private static final int BUFFER_SIZE = 2048;
55 private static final StatusLogger LOGGER = StatusLogger.getLogger();
56
57 private final AtomicLong sequenceNo = new AtomicLong();
58 private final ObjectName objectName;
59 private final LoggerContext loggerContext;
60 private String customConfigText;
61
62
63
64
65
66
67
68
69 public LoggerContextAdmin(LoggerContext loggerContext, Executor executor) {
70 super(executor, createNotificationInfo());
71 this.loggerContext = Assert.isNotNull(loggerContext, "loggerContext");
72 try {
73 String ctxName = Server.escape(loggerContext.getName());
74 String name = String.format(PATTERN, ctxName);
75 objectName = new ObjectName(name);
76 } catch (Exception e) {
77 throw new IllegalStateException(e);
78 }
79 loggerContext.addPropertyChangeListener(this);
80 }
81
82 private static MBeanNotificationInfo createNotificationInfo() {
83 String[] notifTypes = new String[] {
84 NOTIF_TYPE_RECONFIGURED };
85 String name = Notification.class.getName();
86 String description = "Configuration reconfigured";
87 return new MBeanNotificationInfo(notifTypes, name, description);
88 }
89
90 @Override
91 public String getStatus() {
92 return loggerContext.getStatus().toString();
93 }
94
95 @Override
96 public String getName() {
97 return loggerContext.getName();
98 }
99
100 private Configuration getConfig() {
101 return loggerContext.getConfiguration();
102 }
103
104 @Override
105 public String getConfigLocationURI() {
106 if (loggerContext.getConfigLocation() != null) {
107 return String.valueOf(loggerContext.getConfigLocation());
108 }
109 if (getConfigName() != null) {
110 return String.valueOf(new File(getConfigName()).toURI());
111 }
112 return "";
113 }
114
115 @Override
116 public void setConfigLocationURI(String configLocation)
117 throws URISyntaxException, IOException {
118 LOGGER.debug("---------");
119 LOGGER.debug("Remote request to reconfigure using location "
120 + configLocation);
121 URI uri = new URI(configLocation);
122
123
124
125 uri.toURL().openStream().close();
126
127 loggerContext.setConfigLocation(uri);
128 LOGGER.debug("Completed remote request to reconfigure.");
129 }
130
131 @Override
132 public void propertyChange(PropertyChangeEvent evt) {
133 if (!LoggerContext.PROPERTY_CONFIG.equals(evt.getPropertyName())) {
134 return;
135 }
136
137 if (loggerContext.getConfiguration().getName() != null) {
138 customConfigText = null;
139 }
140 Notification notif = new Notification(NOTIF_TYPE_RECONFIGURED,
141 getObjectName(), nextSeqNo(), now(), null);
142 sendNotification(notif);
143 }
144
145 @Override
146 public String getConfigText() throws IOException {
147 if (customConfigText != null) {
148 return customConfigText;
149 }
150 try {
151 return readContents(new URI(getConfigLocationURI()));
152 } catch (Exception ex) {
153 StringWriter sw = new StringWriter(BUFFER_SIZE);
154 ex.printStackTrace(new PrintWriter(sw));
155 return sw.toString();
156 }
157 }
158
159 @Override
160 public void setConfigText(String configText, String charsetName) {
161 String old = customConfigText;
162 customConfigText = Assert.isNotNull(configText, "configText");
163 LOGGER.debug("---------");
164 LOGGER.debug("Remote request to reconfigure from config text.");
165
166 try {
167 InputStream in = new ByteArrayInputStream(
168 configText.getBytes(charsetName));
169 ConfigurationSource source = new ConfigurationSource(in);
170 Configuration updated = ConfigurationFactory.getInstance()
171 .getConfiguration(source);
172 loggerContext.start(updated);
173 LOGGER.debug("Completed remote request to reconfigure from config text.");
174 } catch (Exception ex) {
175 customConfigText = old;
176 String msg = "Could not reconfigure from config text";
177 LOGGER.error(msg, ex);
178 throw new IllegalArgumentException(msg, ex);
179 }
180 }
181
182 private String readContents(URI uri) throws IOException {
183 InputStream in = null;
184 try {
185 in = uri.toURL().openStream();
186 Reader reader = new InputStreamReader(in);
187 StringBuilder result = new StringBuilder(TEXT_BUFFER);
188 char[] buff = new char[PAGE];
189 int count = -1;
190 while ((count = reader.read(buff)) >= 0) {
191 result.append(buff, 0, count);
192 }
193 return result.toString();
194 } finally {
195 try {
196 in.close();
197 } catch (Exception ignored) {
198
199 }
200 }
201 }
202
203 @Override
204 public String getConfigName() {
205 return getConfig().getName();
206 }
207
208 @Override
209 public String getConfigClassName() {
210 return getConfig().getClass().getName();
211 }
212
213 @Override
214 public String getConfigFilter() {
215 return String.valueOf(getConfig().getFilter());
216 }
217
218 @Override
219 public String getConfigMonitorClassName() {
220 return getConfig().getConfigurationMonitor().getClass().getName();
221 }
222
223 @Override
224 public Map<String, String> getConfigProperties() {
225 return getConfig().getProperties();
226 }
227
228
229
230
231
232
233
234 public ObjectName getObjectName() {
235 return objectName;
236 }
237
238 private long nextSeqNo() {
239 return sequenceNo.getAndIncrement();
240 }
241
242 private long now() {
243 return System.currentTimeMillis();
244 }
245 }