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