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