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.log4j.chainsaw.receivers;
18  
19  
20  import java.beans.BeanInfo;
21  import java.beans.Introspector;
22  import java.beans.PropertyDescriptor;
23  import java.io.File;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStreamReader;
27  import java.io.LineNumberReader;
28  import java.net.URL;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collections;
32  import java.util.Iterator;
33  import java.util.List;
34  
35  import javax.xml.parsers.DocumentBuilder;
36  import javax.xml.parsers.DocumentBuilderFactory;
37  import javax.xml.transform.OutputKeys;
38  import javax.xml.transform.Transformer;
39  import javax.xml.transform.TransformerFactory;
40  import javax.xml.transform.dom.DOMSource;
41  import javax.xml.transform.stream.StreamResult;
42  
43  import org.apache.log4j.LogManager;
44  import org.apache.log4j.Logger;
45  import org.apache.log4j.chainsaw.plugins.PluginClassLoaderFactory;
46  import org.apache.log4j.plugins.Plugin;
47  import org.apache.log4j.plugins.PluginRegistry;
48  import org.apache.log4j.plugins.Receiver;
49  import org.apache.log4j.spi.LoggerRepository;
50  import org.apache.log4j.spi.LoggerRepositoryEx;
51  import org.w3c.dom.Document;
52  import org.w3c.dom.Element;
53  
54  
55  /**
56   * Helper class to assisit with all the known Receivers.
57   * 
58   * A local resource 'known.receivers' is read in on initialization
59   * with each line representing the FQN of the Class that is a recognised Receiver.
60   * 
61   * @author Paul Smith <psmith@apache.org>
62   *
63   */
64  public class ReceiversHelper {
65  
66      private static final ReceiversHelper instance = new ReceiversHelper();
67  
68      private final Logger logger = LogManager.getLogger(ReceiversHelper.class);
69      private List receiverClassList = new ArrayList();
70      /**
71       *
72       */
73      private ReceiversHelper() {
74  
75          URL url = this.getClass().getClassLoader().getResource(
76              this.getClass().getPackage().getName().replace('.','/') + "/known.receivers");
77          if (url == null) {
78              logger.warn("Failed to locate known.receivers file");
79              return;
80          }
81          LineNumberReader stream = null;
82          try {
83  
84              stream = new LineNumberReader(new InputStreamReader(url.openStream()));
85              String line;
86              // we need the special Classloader, because under Web start, optional jars might be local
87              // to this workstation
88              ClassLoader classLoader = PluginClassLoaderFactory.getInstance().getClassLoader();
89  
90              while ((line = stream.readLine()) != null) {
91              	
92              	try {
93              		if (line.startsWith("#") || (line.length() == 0)) {
94              			continue;
95              		}
96              		Class receiverClass = classLoader.loadClass(line);
97              		receiverClassList.add(receiverClass);
98              		logger.debug("Located known Receiver class " + receiverClass.getName());
99              	} catch (ClassNotFoundException e) {
100             		logger.warn("Failed to locate Receiver class:" + line);
101             	}
102             	catch (NoClassDefFoundError e) {
103             		logger.error("Failed to locate Receiver class:" + line + ", looks like a dependent class is missing from the classpath", e);
104             	}
105             }
106         } catch (Exception e) {
107             e.printStackTrace();
108         } finally {
109             if (stream != null) {
110                 try {
111                     stream.close();
112                 } catch (IOException ioe) {
113                     ioe.printStackTrace();
114                 }
115             }
116         }
117     }
118 
119 
120     public static ReceiversHelper getInstance() {
121         return instance;
122     }
123 
124 
125     /**
126      * Returns an unmodifiable list of Class objects which represent all the 'known'
127      * Receiver classes.
128      * @return known receiver classes
129      */
130     public List getKnownReceiverClasses() {
131       return Collections.unmodifiableList(receiverClassList);
132     }
133 
134 
135   public void saveReceiverConfiguration(File file) {
136     LoggerRepository repo = LogManager.getLoggerRepository();
137     PluginRegistry pluginRegistry = ((LoggerRepositoryEx) repo).getPluginRegistry();
138     List fullPluginList = pluginRegistry.getPlugins();
139     List pluginList = new ArrayList();
140     for (Iterator iter = fullPluginList.iterator();iter.hasNext();) {
141         Plugin thisPlugin = (Plugin)iter.next();
142         if (thisPlugin instanceof Receiver) {
143             pluginList.add(thisPlugin);
144         }
145     }
146     //remove everything that isn't a receiver..otherwise, we'd create an empty config file
147     try {
148         if (pluginList.size() > 0) {
149             //we programmatically register the ZeroConf plugin in the plugin registry
150             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
151             factory.setNamespaceAware(true);
152             DocumentBuilder builder = factory.newDocumentBuilder();
153             Document document = builder.newDocument();
154             Element rootElement = document.createElementNS("http://jakarta.apache.org/log4j/", "configuration");
155             rootElement.setPrefix("log4j");
156             rootElement.setAttribute("xmlns:log4j", "http://jakarta.apache.org/log4j/");
157             rootElement.setAttribute("debug", "true");
158 
159             for (int i = 0; i < pluginList.size(); i++) {
160                 Receiver receiver;
161 
162                 if (pluginList.get(i) instanceof Receiver) {
163                     receiver = (Receiver) pluginList.get(i);
164                 } else {
165                     continue;
166                 }
167 
168                 Element pluginElement = document.createElement("plugin");
169                 pluginElement.setAttribute("name", receiver.getName());
170                 pluginElement.setAttribute("class", receiver.getClass().getName());
171 
172                 BeanInfo beanInfo = Introspector.getBeanInfo(receiver.getClass());
173                 List list = new ArrayList(Arrays.asList(beanInfo.getPropertyDescriptors()));
174 
175                 for (int j = 0; j < list.size(); j++) {
176                     PropertyDescriptor d = (PropertyDescriptor) list.get(j);
177                     //don't serialize the loggerRepository property for subclasses of componentbase..
178                     //easier to change this than tweak componentbase right now..
179                     if (d.getReadMethod().getName().equals("getLoggerRepository")) {
180                         continue;
181                     }
182                     Object o = d.getReadMethod().invoke(receiver, new Object[] {} );
183                     if (o != null) {
184                         Element paramElement = document.createElement("param");
185                         paramElement.setAttribute("name", d.getName());
186                         paramElement.setAttribute("value", o.toString());
187                         pluginElement.appendChild(paramElement);
188                     }
189                 }
190 
191                 rootElement.appendChild(pluginElement);
192 
193             }
194 
195             TransformerFactory transformerFactory = TransformerFactory.newInstance();
196             Transformer transformer = transformerFactory.newTransformer();
197             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
198             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
199             DOMSource source = new DOMSource(rootElement);
200             FileOutputStream stream = new FileOutputStream(file);
201             StreamResult result = new StreamResult(stream);
202             transformer.transform(source, result);
203             stream.close();
204         }
205 
206     } catch (Exception e) {
207         e.printStackTrace();
208     }
209   }
210 }