1
2
3
4
5
6 package dev.metaschema.databind.codegen;
7
8 import org.apache.logging.log4j.LogManager;
9 import org.apache.logging.log4j.Logger;
10 import org.eclipse.jdt.annotation.Owning;
11
12 import java.io.IOException;
13 import java.lang.module.ModuleDescriptor;
14 import java.net.MalformedURLException;
15 import java.net.URL;
16 import java.net.URLClassLoader;
17 import java.nio.file.Path;
18 import java.security.AccessController;
19 import java.security.PrivilegedAction;
20 import java.util.Arrays;
21 import java.util.List;
22 import java.util.stream.Collectors;
23
24 import javax.tools.DiagnosticCollector;
25
26 import dev.metaschema.core.model.IModule;
27 import dev.metaschema.core.util.ObjectUtils;
28 import dev.metaschema.databind.IBindingContext;
29 import dev.metaschema.databind.codegen.config.DefaultBindingConfiguration;
30 import dev.metaschema.databind.codegen.config.IBindingConfiguration;
31 import edu.umd.cs.findbugs.annotations.NonNull;
32
33
34
35
36
37
38
39 public final class ModuleCompilerHelper {
40 private static final Logger LOGGER = LogManager.getLogger(ModuleCompilerHelper.class);
41
42 private ModuleCompilerHelper() {
43
44 }
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 @SuppressWarnings("resource")
60 @Owning
61 @NonNull
62 public static ClassLoader newClassLoader(
63 @NonNull final Path classDir,
64 @NonNull final ClassLoader parent) {
65 return ObjectUtils.notNull(AccessController.doPrivileged(
66 (PrivilegedAction<ClassLoader>) () -> {
67 try {
68 return new URLClassLoader(new URL[] { classDir.toUri().toURL() }, parent);
69 } catch (MalformedURLException ex) {
70 throw new IllegalStateException("unable to configure class loader", ex);
71 }
72 }));
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 @NonNull
89 public static IProduction compileMetaschema(
90 @NonNull IModule module,
91 @NonNull Path classDir)
92 throws IOException {
93 return compileModule(module, classDir, new DefaultBindingConfiguration());
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 @NonNull
113 public static IProduction compileModule(
114 @NonNull IModule module,
115 @NonNull Path classDir,
116 @NonNull IBindingConfiguration bindingConfiguration) throws IOException {
117 IProduction production = JavaGenerator.generate(module, classDir, bindingConfiguration);
118 List<IGeneratedClass> classesToCompile = production.getGeneratedClasses().collect(Collectors.toList());
119
120 List<Path> classes = ObjectUtils.notNull(classesToCompile.stream()
121 .map(IGeneratedClass::getClassFile)
122 .collect(Collectors.toUnmodifiableList()));
123
124
125 JavaCompilerSupport compiler = new JavaCompilerSupport(classDir);
126 compiler.setLogger(new JavaCompilerSupport.Logger() {
127
128 @Override
129 public boolean isInfoEnabled() {
130 return LOGGER.isInfoEnabled();
131 }
132
133 @Override
134 public boolean isDebugEnabled() {
135 return LOGGER.isDebugEnabled();
136 }
137
138 @Override
139 public void info(String msg) {
140 LOGGER.atInfo().log(msg);
141 }
142
143 @Override
144 public void debug(String msg) {
145 LOGGER.atDebug().log(msg);
146 }
147 });
148
149
150 boolean useModulePath = false;
151 Module databindModule = IBindingContext.class.getModule();
152 if (databindModule != null) {
153 ModuleDescriptor descriptor = databindModule.getDescriptor();
154 if (descriptor != null) {
155
156 compiler.addRootModule(ObjectUtils.notNull(descriptor.name()));
157 useModulePath = true;
158 }
159 }
160
161 handleClassAndModulePath(compiler, useModulePath);
162
163
164 JavaCompilerSupport.CompilationResult result = compiler.compile(classes);
165
166 if (!result.isSuccessful()) {
167
168 DiagnosticCollector<?> diagnostics = new DiagnosticCollector<>();
169 if (LOGGER.isErrorEnabled()) {
170 LOGGER.error(diagnostics.getDiagnostics().toString());
171 }
172 throw new IllegalStateException(String.format("failed to compile classes: %s%nClasspath: %s%nModule Path: %s%n%s",
173 classesToCompile.stream()
174 .map(clazz -> clazz.getClassName().canonicalName())
175 .collect(Collectors.joining(",")),
176 diagnostics.getDiagnostics().toString(),
177 compiler.getClassPath().stream()
178 .collect(Collectors.joining(":")),
179 compiler.getModulePath().stream()
180 .collect(Collectors.joining(":"))));
181 }
182 return production;
183 }
184
185 private static void handleClassAndModulePath(JavaCompilerSupport compiler, boolean useModulePath) {
186 String classPath = System.getProperty("java.class.path");
187 String modulePath = System.getProperty("jdk.module.path");
188 if (useModulePath) {
189
190 if (classPath != null) {
191 Arrays.stream(classPath.split(":")).forEachOrdered(compiler::addToClassPath);
192 }
193
194 if (modulePath != null) {
195 Arrays.stream(modulePath.split(":")).forEachOrdered(compiler::addToModulePath);
196 }
197 } else {
198
199 if (classPath != null) {
200 Arrays.stream(classPath.split(":")).forEachOrdered(compiler::addToClassPath);
201 }
202
203 if (modulePath != null) {
204 Arrays.stream(modulePath.split(":")).forEachOrdered(compiler::addToClassPath);
205 }
206 }
207
208 }
209 }