View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.pmd.exec;
20  
21  import java.io.BufferedInputStream;
22  import java.io.BufferedOutputStream;
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.io.UnsupportedEncodingException;
28  import java.net.URL;
29  import java.net.URLClassLoader;
30  import java.net.URLDecoder;
31  import java.nio.charset.StandardCharsets;
32  import java.util.logging.Handler;
33  import java.util.logging.Level;
34  import java.util.logging.SimpleFormatter;
35  
36  import org.apache.maven.cli.logging.Slf4jConfiguration;
37  import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
38  import org.codehaus.plexus.logging.console.ConsoleLogger;
39  import org.slf4j.ILoggerFactory;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  import org.slf4j.bridge.SLF4JBridgeHandler;
43  
44  abstract class Executor {
45      private static final Logger LOG = LoggerFactory.getLogger(Executor.class);
46  
47      /**
48       * This holds a strong reference in case we configured the logger to
49       * redirect to slf4j. See {@link #showPmdLog}. Without a strong reference,
50       * the logger might be garbage collected and the redirect to slf4j is gone.
51       */
52      private java.util.logging.Logger julLogger;
53  
54      protected void setupPmdLogging(boolean showPmdLog, String logLevel) {
55          if (!showPmdLog) {
56              return;
57          }
58  
59          java.util.logging.Logger logger = java.util.logging.Logger.getLogger("net.sourceforge.pmd");
60  
61          boolean slf4jBridgeAlreadyAdded = false;
62          for (Handler handler : logger.getHandlers()) {
63              if (handler instanceof SLF4JBridgeHandler) {
64                  slf4jBridgeAlreadyAdded = true;
65                  break;
66              }
67          }
68  
69          if (slf4jBridgeAlreadyAdded) {
70              return;
71          }
72  
73          SLF4JBridgeHandler handler = new SLF4JBridgeHandler();
74          SimpleFormatter formatter = new SimpleFormatter();
75          handler.setFormatter(formatter);
76          logger.setUseParentHandlers(false);
77          logger.addHandler(handler);
78          handler.setLevel(Level.ALL);
79          logger.setLevel(Level.ALL);
80          julLogger = logger;
81          julLogger.fine("Configured jul-to-slf4j bridge for " + logger.getName());
82      }
83  
84      protected void setupLogLevel(String logLevel) {
85          ILoggerFactory slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
86          Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
87          if ("debug".equals(logLevel)) {
88              slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
89          } else if ("info".equals(logLevel)) {
90              slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.INFO);
91          } else {
92              slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
93          }
94          slf4jConfiguration.activate();
95      }
96  
97      protected static String buildClasspath() {
98          StringBuilder classpath = new StringBuilder();
99  
100         // plugin classpath needs to come first
101         ClassLoader pluginClassloader = Executor.class.getClassLoader();
102         buildClasspath(classpath, pluginClassloader);
103 
104         ClassLoader coreClassloader = ConsoleLogger.class.getClassLoader();
105         buildClasspath(classpath, coreClassloader);
106 
107         return classpath.toString();
108     }
109 
110     static void buildClasspath(StringBuilder classpath, ClassLoader cl) {
111         if (cl instanceof URLClassLoader) {
112             for (URL url : ((URLClassLoader) cl).getURLs()) {
113                 if ("file".equalsIgnoreCase(url.getProtocol())) {
114                     try {
115                         String filename = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8.name());
116                         classpath.append(new File(filename).getPath()).append(File.pathSeparatorChar);
117                     } catch (UnsupportedEncodingException e) {
118                         LOG.warn("Ignoring " + url + " in classpath due to UnsupportedEncodingException", e);
119                     }
120                 }
121             }
122         }
123     }
124 
125     protected static class ProcessStreamHandler implements Runnable {
126         private static final int BUFFER_SIZE = 8192;
127 
128         private final BufferedInputStream in;
129         private final BufferedOutputStream out;
130 
131         public static void start(InputStream in, OutputStream out) {
132             Thread t = new Thread(new ProcessStreamHandler(in, out));
133             t.start();
134         }
135 
136         private ProcessStreamHandler(InputStream in, OutputStream out) {
137             this.in = new BufferedInputStream(in);
138             this.out = new BufferedOutputStream(out);
139         }
140 
141         @Override
142         public void run() {
143             byte[] buffer = new byte[BUFFER_SIZE];
144             try {
145                 int count = in.read(buffer);
146                 while (count != -1) {
147                     out.write(buffer, 0, count);
148                     out.flush();
149                     count = in.read(buffer);
150                 }
151                 out.flush();
152             } catch (IOException e) {
153                 LOG.error(e.getMessage(), e);
154             }
155         }
156     }
157 }