• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.googlejavaformat.intellij;
18 
19 import com.google.common.base.Suppliers;
20 import com.intellij.ide.ui.IdeUiService;
21 import com.intellij.notification.Notification;
22 import com.intellij.notification.NotificationType;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.project.Project;
25 import java.util.function.Supplier;
26 
27 class JreConfigurationChecker {
28 
29   private static final Supplier<Boolean> hasAccess =
30       Suppliers.memoize(JreConfigurationChecker::checkJreConfiguration);
31   private static final Logger logger = Logger.getInstance(JreConfigurationChecker.class);
32 
33   private final Project project;
34 
JreConfigurationChecker(Project project)35   public JreConfigurationChecker(Project project) {
36     this.project = project;
37   }
38 
checkJreConfiguration(Project project)39   static boolean checkJreConfiguration(Project project) {
40     var success = hasAccess.get();
41     if (!success) {
42       project.getService(JreConfigurationChecker.class).displayConfigurationErrorNotification();
43     }
44     return success;
45   }
46 
47   /**
48    * Determine whether the JRE is configured to work with the google-java-format plugin. If not,
49    * display a notification with instructions and return false.
50    */
checkJreConfiguration()51   private static boolean checkJreConfiguration() {
52     try {
53       return testClassAccess(
54           "com.sun.tools.javac.api.JavacTrees",
55           "com.sun.tools.javac.code.Flags",
56           "com.sun.tools.javac.file.JavacFileManager",
57           "com.sun.tools.javac.parser.JavacParser",
58           "com.sun.tools.javac.tree.JCTree",
59           "com.sun.tools.javac.util.Log");
60     } catch (ClassNotFoundException e) {
61       logger.error("Error checking jre configuration for google-java-format", e);
62       return false;
63     }
64   }
65 
testClassAccess(String... classNames)66   private static boolean testClassAccess(String... classNames) throws ClassNotFoundException {
67     for (String className : classNames) {
68       if (!testClassAccess(className)) {
69         return false;
70       }
71     }
72     return true;
73   }
74 
testClassAccess(String className)75   private static boolean testClassAccess(String className) throws ClassNotFoundException {
76     Class<?> klass = Class.forName(className);
77     return klass
78         .getModule()
79         // isExported returns true if the package is either open or exported. Either one is
80         // sufficient
81         // to run the google-java-format code (even though the documentation specifies --add-opens).
82         .isExported(
83             klass.getPackageName(),
84             JreConfigurationChecker.class.getClassLoader().getUnnamedModule());
85   }
86 
displayConfigurationErrorNotification()87   private void displayConfigurationErrorNotification() {
88     Notification notification =
89         new Notification(
90             "Configure JRE for google-java-format",
91             "Configure the JRE for google-java-format",
92             "The google-java-format plugin needs additional configuration before it can be used. "
93                 + "<a href=\"instructions\">Follow the instructions here</a>.",
94             NotificationType.INFORMATION);
95     notification.setListener(
96         (n, e) -> {
97           IdeUiService.getInstance()
98               .browse(
99                   "https://github.com/google/google-java-format/blob/master/README.md#intellij-jre-config");
100           n.expire();
101         });
102     notification.notify(project);
103   }
104 }
105