1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.tools.sjavac.comp;
  26 
  27 import java.io.File;
  28 import java.io.IOException;
  29 import java.io.PrintWriter;
  30 import java.io.StringWriter;
  31 import java.net.URI;
  32 import java.nio.file.Paths;
  33 import java.util.Arrays;
  34 import java.util.List;
  35 import java.util.Set;
  36 
  37 import javax.tools.JavaFileObject;
  38 import javax.tools.StandardJavaFileManager;
  39 
  40 import com.sun.source.tree.CompilationUnitTree;
  41 import com.sun.tools.javac.api.JavacTaskImpl;
  42 import com.sun.tools.javac.api.JavacTool;
  43 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  44 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  45 import com.sun.tools.javac.util.Context;
  46 import com.sun.tools.javac.util.ListBuffer;
  47 import com.sun.tools.javac.util.Options;
  48 import com.sun.tools.sjavac.Util;
  49 import com.sun.tools.sjavac.comp.dependencies.DependencyCollector;
  50 import com.sun.tools.sjavac.comp.dependencies.PublicApiCollector;
  51 import com.sun.tools.sjavac.server.CompilationResult;
  52 import com.sun.tools.sjavac.server.Sjavac;
  53 import com.sun.tools.sjavac.server.SysInfo;
  54 
  55 /**
  56  * The sjavac implementation that interacts with javac and performs the actual
  57  * compilation.
  58  *
  59  *  <p><b>This is NOT part of any supported API.
  60  *  If you write code that depends on this, you do so at your own risk.
  61  *  This code and its internal interfaces are subject to change or
  62  *  deletion without notice.</b>
  63  */
  64 public class SjavacImpl implements Sjavac {
  65 
  66     @Override
  67     public SysInfo getSysInfo() {
  68         return new SysInfo(Runtime.getRuntime().availableProcessors(),
  69                            Runtime.getRuntime().maxMemory());
  70     }
  71 
  72     @Override
  73     public CompilationResult compile(String protocolId,
  74                                      String invocationId,
  75                                      String[] args,
  76                                      List<File> explicitSources,
  77                                      Set<URI> sourcesToCompile,
  78                                      Set<URI> visibleSources) {
  79         JavacTool compiler = JavacTool.create();
  80         try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
  81             SmartFileManager smartFileManager = new SmartFileManager(fileManager);
  82             Context context = new Context();
  83 
  84             // Now setup the actual compilation....
  85             CompilationResult compilationResult = new CompilationResult(0);
  86 
  87             // First deal with explicit source files on cmdline and in at file.
  88             ListBuffer<JavaFileObject> compilationUnits = new ListBuffer<>();
  89             for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(explicitSources)) {
  90                 compilationUnits.append(i);
  91             }
  92             // Now deal with sources supplied as source_to_compile.
  93             ListBuffer<File> sourcesToCompileFiles = new ListBuffer<>();
  94             for (URI u : sourcesToCompile) {
  95                 sourcesToCompileFiles.append(new File(u));
  96             }
  97             for (JavaFileObject i : fileManager.getJavaFileObjectsFromFiles(sourcesToCompileFiles)) {
  98                 compilationUnits.append(i);
  99             }
 100 
 101             // Create a new logger.
 102             StringWriter stdoutLog = new StringWriter();
 103             StringWriter stderrLog = new StringWriter();
 104             PrintWriter stdout = new PrintWriter(stdoutLog);
 105             PrintWriter stderr = new PrintWriter(stderrLog);
 106             com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
 107             DependencyCollector depsCollector = new DependencyCollector();
 108             PublicApiCollector pubApiCollector = new PublicApiCollector();
 109             PathAndPackageVerifier papVerifier = new PathAndPackageVerifier();
 110             try {
 111                 if (compilationUnits.size() > 0) {
 112                     smartFileManager.setVisibleSources(visibleSources);
 113                     smartFileManager.cleanArtifacts();
 114                     smartFileManager.setLog(stdout);
 115 
 116                     // Do the compilation!
 117                     JavacTaskImpl task =
 118                             (JavacTaskImpl) compiler.getTask(stderr,
 119                                                              smartFileManager,
 120                                                              null,
 121                                                              Arrays.asList(args),
 122                                                              null,
 123                                                              compilationUnits,
 124                                                              context);
 125                     smartFileManager.setSymbolFileEnabled(!Options.instance(context).isSet("ignore.symbol.file"));
 126                     task.addTaskListener(depsCollector);
 127                     task.addTaskListener(pubApiCollector);
 128                     task.addTaskListener(papVerifier);
 129                     rc = task.doCall();
 130                     smartFileManager.flush();
 131                 }
 132             } catch (Exception e) {
 133                 stderrLog.append(Util.getStackTrace(e));
 134                 rc = com.sun.tools.javac.main.Main.Result.ERROR;
 135             }
 136 
 137             compilationResult.packageArtifacts = smartFileManager.getPackageArtifacts();
 138 
 139             Dependencies deps = Dependencies.instance(context);
 140             for (PackageSymbol from : depsCollector.getSourcePackages()) {
 141                 for (PackageSymbol to : depsCollector.getDependenciesForPkg(from))
 142                     deps.collect(from.fullname, to.fullname);
 143             }
 144 
 145             for (ClassSymbol cs : pubApiCollector.getClassSymbols())
 146                 deps.visitPubapi(cs);
 147 
 148             if (papVerifier.getMisplacedCompilationUnits().size() > 0) {
 149                 for (CompilationUnitTree cu : papVerifier.getMisplacedCompilationUnits()) {
 150                     System.err.println("Misplaced compilation unit.");
 151                     System.err.println("    Directory: " + Paths.get(cu.getSourceFile().toUri()).getParent());
 152                     System.err.println("    Package:   " + cu.getPackageName());
 153                 }
 154                 rc = com.sun.tools.javac.main.Main.Result.ERROR;
 155             }
 156 
 157             compilationResult.packageDependencies = deps.getDependencies();
 158             compilationResult.packagePubapis = deps.getPubapis();
 159             compilationResult.stdout = stdoutLog.toString();
 160             compilationResult.stderr = stderrLog.toString();
 161             compilationResult.returnCode = rc.exitCode;
 162 
 163             return compilationResult;
 164         } catch (IOException e) {
 165             throw new Error(e);
 166         }
 167     }
 168 
 169     @Override
 170     public void shutdown() {
 171         // Nothing to clean up
 172         // ... maybe we should wait for any current request to finish?
 173     }
 174 
 175 
 176     @Override
 177     public String serverSettings() {
 178         return "";
 179     }
 180 
 181 }