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