cleanup (inspection "Java | Class structure | Utility class is not 'final'")
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / cmdline / ClasspathBootstrap.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.jps.cmdline;
3
4 import com.google.gson.Gson;
5 import com.google.protobuf.Message;
6 import com.intellij.compiler.notNullVerification.NotNullVerifyingInstrumenter;
7 import com.intellij.openapi.application.PathManager;
8 import com.intellij.openapi.diagnostic.Logger;
9 import com.intellij.openapi.util.io.FileUtil;
10 import com.intellij.uiDesigner.compiler.AlienFormFileException;
11 import com.intellij.uiDesigner.core.GridConstraints;
12 import com.intellij.util.SystemProperties;
13 import com.intellij.util.containers.ContainerUtil;
14 import com.jgoodies.forms.layout.CellConstraints;
15 import com.thoughtworks.qdox.JavaProjectBuilder;
16 import io.netty.buffer.ByteBufAllocator;
17 import io.netty.channel.EventLoopGroup;
18 import io.netty.handler.codec.protobuf.ProtobufDecoder;
19 import io.netty.resolver.AddressResolverGroup;
20 import io.netty.util.NetUtil;
21 import net.n3.nanoxml.IXMLBuilder;
22 import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager;
23 import org.jetbrains.jps.builders.impl.java.EclipseCompilerTool;
24 import org.jetbrains.jps.builders.java.JavaCompilingTool;
25 import org.jetbrains.jps.builders.java.JavaSourceTransformer;
26 import org.jetbrains.jps.javac.ExternalJavacProcess;
27 import org.jetbrains.jps.model.JpsModel;
28 import org.jetbrains.jps.model.impl.JpsModelImpl;
29 import org.jetbrains.jps.model.serialization.JpsProjectLoader;
30 import org.jetbrains.org.objectweb.asm.ClassVisitor;
31 import org.jetbrains.org.objectweb.asm.ClassWriter;
32
33 import javax.tools.*;
34 import java.io.File;
35 import java.util.*;
36
37 /**
38  * @author Eugene Zhuravlev
39  */
40 public final class ClasspathBootstrap {
41   private static final Logger LOG = Logger.getInstance(ClasspathBootstrap.class);
42
43   private ClasspathBootstrap() { }
44
45   private static final Class<?>[] COMMON_REQUIRED_CLASSES = {
46     Message.class, // protobuf
47     NetUtil.class, // netty common
48     EventLoopGroup.class, // netty transport
49     AddressResolverGroup.class, // netty resolver
50     ByteBufAllocator.class, // netty buffer
51     ProtobufDecoder.class,  // netty codec
52   };
53
54   public static List<String> getBuildProcessApplicationClasspath() {
55     final Set<String> cp = new HashSet<>();
56
57     cp.add(getResourcePath(BuildMain.class));
58     cp.add(getResourcePath(ExternalJavacProcess.class));  // intellij.platform.jps.build.javac.rt part
59
60     cp.addAll(PathManager.getUtilClassPath()); // intellij.platform.util
61
62     for (Class<?> aClass : COMMON_REQUIRED_CLASSES) {
63       cp.add(getResourcePath(aClass));
64     }
65
66     cp.add(getResourcePath(ClassWriter.class));  // asm
67     cp.add(getResourcePath(ClassVisitor.class));  // asm-commons
68     cp.add(getResourcePath(JpsModel.class));  // intellij.platform.jps.model
69     cp.add(getResourcePath(JpsModelImpl.class));  // intellij.platform.jps.model.impl
70     cp.add(getResourcePath(JpsProjectLoader.class));  // intellij.platform.jps.model.serialization
71     cp.add(getResourcePath(AlienFormFileException.class));  // intellij.java.guiForms.compiler
72     cp.add(getResourcePath(GridConstraints.class));  // intellij.java.guiForms.rt
73     cp.add(getResourcePath(CellConstraints.class));  // jGoodies-forms
74     cp.addAll(getInstrumentationUtilRoots());
75     cp.add(getResourcePath(IXMLBuilder.class));  // nano-xml
76     cp.add(getResourcePath(JavaProjectBuilder.class));  // QDox lightweight java parser
77     cp.add(getResourcePath(Gson.class));  // gson
78
79     cp.addAll(ContainerUtil.map(ArtifactRepositoryManager.getClassesFromDependencies(), ClasspathBootstrap::getResourcePath));
80
81     cp.addAll(getJavac8RefScannerClasspath());
82     //don't forget to update CommunityStandaloneJpsBuilder.layoutJps accordingly
83
84     try {
85       final Class<?> cmdLineWrapper = Class.forName("com.intellij.rt.execution.CommandLineWrapper");
86       cp.add(getResourcePath(cmdLineWrapper));  // idea_rt.jar
87     }
88     catch (Throwable ignored) { }
89
90     return new ArrayList<>(cp);
91   }
92
93   public static void appendJavaCompilerClasspath(Collection<? super String> cp, boolean includeEcj) {
94     if (includeEcj) {
95       File file = EclipseCompilerTool.findEcjJarFile();
96       if (file != null) {
97         cp.add(file.getAbsolutePath());
98       }
99     }
100   }
101
102   public static List<File> getExternalJavacProcessClasspath(String sdkHome, JavaCompilingTool compilingTool) {
103     final Set<File> cp = new LinkedHashSet<>();
104     cp.add(getResourceFile(ExternalJavacProcess.class)); // self
105     // util
106     for (String path : PathManager.getUtilClassPath()) {
107       cp.add(new File(path));
108     }
109
110     for (Class<?> aClass : COMMON_REQUIRED_CLASSES) {
111       cp.add(getResourceFile(aClass));
112     }
113
114     try {
115       final Class<?> cmdLineWrapper = Class.forName("com.intellij.rt.execution.CommandLineWrapper");
116       cp.add(getResourceFile(cmdLineWrapper));  // idea_rt.jar
117     }
118     catch (Throwable th) {
119       LOG.info(th);
120     }
121
122     try {
123       final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
124       // sdkHome is not the same as the sdk used to run this process
125       final File candidate = new File(sdkHome, "lib/tools.jar");
126       if (candidate.exists()) {
127         cp.add(candidate);
128       }
129       else {
130         // last resort
131         final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
132         Class<?> compilerClass;
133         if (systemCompiler != null) {
134           compilerClass = systemCompiler.getClass();
135         }
136         else {
137           compilerClass = Class.forName("com.sun.tools.javac.api.JavacTool", false, ClasspathBootstrap.class.getClassLoader());
138         }
139         String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(compilerClass).getPath());
140         String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
141         if (relPath != null) {
142           if (relPath.contains("..")) {
143             relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
144           }
145           if (relPath != null) {
146             final File targetFile = new File(sdkHome, relPath);
147             cp.add(targetFile);  // tools.jar
148           }
149         }
150       }
151     }
152     catch (Throwable th) {
153       LOG.info(th);
154     }
155
156     cp.addAll(compilingTool.getAdditionalClasspath());
157
158     for (JavaSourceTransformer t : JavaSourceTransformer.getTransformers()) {
159       cp.add(getResourceFile(t.getClass()));
160     }
161
162     return new ArrayList<>(cp);
163   }
164
165   public static String getResourcePath(Class<?> aClass) {
166     return PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class");
167   }
168
169   public static File getResourceFile(Class<?> aClass) {
170     return new File(getResourcePath(aClass));
171   }
172
173   private static List<String> getInstrumentationUtilRoots() {
174     String instrumentationUtilPath = getResourcePath(NotNullVerifyingInstrumenter.class);
175     File instrumentationUtil = new File(instrumentationUtilPath);
176     if (instrumentationUtil.isDirectory()) {
177       //running from sources: load classes from .../out/production/intellij.java.compiler.instrumentationUtil.java8
178       return Arrays.asList(instrumentationUtilPath, new File(instrumentationUtil.getParentFile(), "intellij.java.compiler.instrumentationUtil.java8").getAbsolutePath());
179     }
180     else {
181       //running from jars: intellij.java.compiler.instrumentationUtil.java8 is located in the same jar
182       return Collections.singletonList(instrumentationUtilPath);
183     }
184   }
185
186   private static List<String> getJavac8RefScannerClasspath() {
187     String instrumentationPath = getResourcePath(NotNullVerifyingInstrumenter.class);
188     File instrumentationUtil = new File(instrumentationPath);
189     if (instrumentationUtil.isDirectory()) {
190       //running from sources: load classes from .../out/production/intellij.java.jps.javacRefScanner8
191       return Collections.singletonList(new File(instrumentationUtil.getParentFile(), "intellij.java.jps.javacRefScanner8").getAbsolutePath());
192     }
193     else {
194       return Collections.singletonList(instrumentationPath);
195     }
196   }
197 }