
io.sarl.lang.compiler.batch.SarlBatchCompiler Maven / Gradle / Ivy
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2024 SARL.io, the Original Authors and Main Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.sarl.lang.compiler.batch;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import org.apache.log4j.Appender;
import org.apache.log4j.Category;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.HierarchyEventListener;
import org.apache.log4j.spi.LoggerFactory;
import org.apache.log4j.spi.LoggerRepository;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtend.core.macro.ProcessorInstanceForJvmTypeProvider;
import org.eclipse.xtext.Constants;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.access.impl.ClasspathTypeProvider;
import org.eclipse.xtext.common.types.access.impl.IndexedJvmTypeAccess;
import org.eclipse.xtext.common.types.descriptions.IStubGenerator;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.generator.GeneratorContext;
import org.eclipse.xtext.generator.GeneratorDelegate;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IOutputConfigurationProvider;
import org.eclipse.xtext.generator.JavaIoFileSystemAccess;
import org.eclipse.xtext.generator.OutputConfiguration;
import org.eclipse.xtext.generator.OutputConfigurationAdapter;
import org.eclipse.xtext.mwe.NameBasedFilter;
import org.eclipse.xtext.mwe.PathTraverser;
import org.eclipse.xtext.parser.IEncodingProvider;
import org.eclipse.xtext.resource.CompilerPhases;
import org.eclipse.xtext.resource.FileExtensionProvider;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.eclipse.xtext.resource.persistence.StorageAwareResource;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.Files;
import org.eclipse.xtext.util.JavaVersion;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.util.UriUtil;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.workspace.FileProjectConfig;
import org.eclipse.xtext.workspace.ProjectConfigAdapter;
import org.eclipse.xtext.xbase.compiler.GeneratorConfig;
import org.eclipse.xtext.xbase.compiler.GeneratorConfigProvider;
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider;
import org.eclipse.xtext.xbase.lib.Inline;
import org.eclipse.xtext.xbase.lib.Pure;
import org.eclipse.xtext.xbase.resource.BatchLinkableResource;
import io.sarl.lang.SARLConfig;
import io.sarl.lang.compiler.GeneratorConfig2;
import io.sarl.lang.compiler.GeneratorConfigProvider2;
import io.sarl.lang.compiler.IGeneratorConfigProvider2;
import io.sarl.lang.compiler.batch.InternalXtextLogger.InternalXtextLoggerFactory;
import io.sarl.lang.extralanguage.IExtraLanguageContribution;
import io.sarl.lang.extralanguage.IExtraLanguageContributions;
import io.sarl.lang.util.Utils;
import io.sarl.lang.validation.IConfigurableIssueSeveritiesProvider;
/** The compiler from SARL that could be used for batch tasks (Maven, CLI).
*
* This compiler is inspired by the Xtend batch compiler.
*
* @author Stéphane Galland
* @version batchcompiler 0.14.0 20241106-161406
* @mavengroupid io.sarl.lang
* @mavenartifactid batchcompiler
* @since 0.5
*/
public class SarlBatchCompiler {
private static final String BINCLASS_FOLDER_PREFIX = "classes"; //$NON-NLS-1$
private static final String STUB_FOLDER_PREFIX = "stubs"; //$NON-NLS-1$
private static final String INTERNAL_ERROR_CODE = SarlBatchCompiler.class.getName() + ".internal_error"; //$NON-NLS-1$
private static final Predicate DISABLER = it -> false;
/** The provider of resource sets.
*/
protected Provider resourceSetProvider;
private File outputPath;
private File classOutputPath;
private File tempPath;
private CleaningPolicy cleaningPolicy = CleaningPolicy.getDefault();
private List classpath;
private List modulepath;
private String encoding;
private boolean writeTraceFiles = true;
private boolean writeStorageFiles = true;
private boolean verbose;
private boolean enableSarlCompilation = true;
private boolean enableJavaPostCompilation;
private List sourcePath;
private boolean useCurrentClassLoaderAsParent;
private org.eclipse.emf.common.util.URI baseUri;
private FileProjectConfig projectConfig;
private Map outputConfigurations;
private ClassLoader currentClassLoader;
private ClassLoader jvmTypesClassLoader;
private ClassLoader annotationProcessingClassLoader;
@Inject
private IGeneratorConfigProvider generatorConfigProvider;
@Inject
private IGeneratorConfigProvider2 generatorConfigProvider2;
@Inject
private IOutputConfigurationProvider outputConfigurationProvider;
@Inject
private CompilerPhases compilerPhases;
@Inject
private Provider javaIoFileSystemAccessProvider;
@Inject
private IndexedJvmTypeAccess indexedJvmTypeAccess;
@Inject
private IEncodingProvider.Runtime encodingProvider;
@Inject
private FileExtensionProvider fileExtensionProvider;
@Inject
private IResourceDescription.Manager resourceDescriptionManager;
@Inject
private IStubGenerator stubGenerator;
@Inject
private GeneratorDelegate generator;
@Inject
private IConfigurableIssueSeveritiesProvider issueSeverityProvider;
@Inject
private IExtraLanguageContributions extraLanguageContributions;
@Inject
@Named(Constants.LANGUAGE_NAME)
private String languageName;
private IJavaBatchCompiler javaCompiler;
private Logger logger;
private IssueMessageFormatter messageFormatter;
private Collection messageListeners = new LinkedList<>();
private Collection resourceReceivers = new LinkedList<>();
private final List tempFolders = new ArrayList<>();
private Comparator issueComparator = new DefaultIssueComparator();
private GeneratorConfig currentGeneratorConfiguration;
private GeneratorConfig2 currentGeneratorConfiguration2;
private String enabledExtraLanguageContributions;
private boolean reportInternalProblemsAsIssues;
private boolean reportWarningsAsErrors;
private OptimizationLevel optimizationLevel;
/** Constructor the batch compiler.
*/
public SarlBatchCompiler() {
//
}
/** Change the Java compiler.
*
* @param compiler the Java compiler
* @since 0.8
*/
@Inject
public void setJavaCompiler(IJavaBatchCompiler compiler) {
assert compiler != null;
this.javaCompiler = compiler;
}
/** Replies the Java compiler.
*
* @return the Java compiler
* @since 0.8
*/
public IJavaBatchCompiler getJavaCompiler() {
if (this.javaCompiler == null) {
this.javaCompiler = SarlBatchCompilerUtils.newDefaultJavaBatchCompiler();
}
return this.javaCompiler;
}
/** Change the optimization level that should be applied to the generated Java byte code.
*
* @param level the optimization level.
* @since 0.8
*/
public void setOptimizationLevel(OptimizationLevel level) {
this.optimizationLevel = level;
}
/** Replies the optimization level that should be applied to the generated Java byte code.
*
* @return the optimization level.
* @since 0.8
*/
public OptimizationLevel getOptimizationLevel() {
if (this.optimizationLevel == null) {
this.optimizationLevel = OptimizationLevel.getDefault();
}
return this.optimizationLevel;
}
/** Change the flag that permits to report the compiler's internal problems as issues.
*
* @param reportAsIssues {@code true} if the internal errors are reported as issues.
* @since 0.8
* @see #addIssueMessageListener(IssueMessageListener)
*/
public void setReportInternalProblemsAsIssues(boolean reportAsIssues) {
this.reportInternalProblemsAsIssues = reportAsIssues;
}
/** Replies the flag that indicates to report the compiler's internal problems as issues.
*
* @return {@code true} if the internal errors are reported as issues.
* @since 0.8
* @see #addIssueMessageListener(IssueMessageListener)
*/
public boolean getReportInternalProblemsAsIssues() {
return this.reportInternalProblemsAsIssues;
}
/** Change the flag that permits to report the warning issues detected by the SARL compiler as errors to the user
* of the batch compiler.
*
* @param reportAsErrors {@code true} if the warnings are reported as errors.
* @since 0.13
* @see #addIssueMessageListener(IssueMessageListener)
*/
public void setReportWarningsAsErrors(boolean reportAsErrors) {
this.reportWarningsAsErrors = reportAsErrors;
}
/** Replies the flag that permits to report the warning issues detected by the SARL compiler as errors to the user
* of the batch compiler.
*
* @return {@code true} if the warnings are reported as errors.
* @since 0.13
* @see #addIssueMessageListener(IssueMessageListener)
*/
public boolean getReportWarningsAsErrors() {
return this.reportWarningsAsErrors;
}
/** Change the extra languages' generators that should be enabled.
*
* @param identifiers the identifier, the identifiers (separated by {@link File#pathSeparator} of the
* extra languages' generator(s) to be enabled. If this parameter is {@code null}, all the extra
* languages' generator are disabled.
* @since 0.8
*/
public void setExtraLanguageGenerators(String identifiers) {
this.enabledExtraLanguageContributions = Strings.emptyIfNull(identifiers);
}
/** Replies the extra languages' generators that should be enabled.
*
* @return the identifier, the identifiers (separated by {@link File#pathSeparator} of the
* extra languages' generator(s) to be enabled. If this parameter is {@code null}, all the extra
* languages' generator are disabled.
* @since 0.8
*/
public String getExtraLanguageGenerators() {
return this.enabledExtraLanguageContributions;
}
/** Set the comparator of issues that is used for sorting the issues before they are logged.
*
* @param comparator the comparator; never {@code null}.
*/
public void setIssueComparator(Comparator comparator) {
if (comparator != null) {
this.issueComparator = comparator;
}
}
/** Replies the comparator of issues that is used for sorting the issues before they are logged.
*
* @return the comparator; never {@code null}.
*/
public Comparator getIssueComparator() {
return this.issueComparator;
}
/** Replies if the Java compiler should be invoked after the SARL compiler is invoked.
*
* @return {@code true} if the Java compiler is invoked after the SARL compiler.
*/
public boolean isJavaPostCompilationEnable() {
return this.enableJavaPostCompilation;
}
/** Set if the Java compiler should be invoked after the SARL compiler is invoked.
*
* @param enable {@code true} if the Java compiler is invoked after the SARL compiler.
*/
public void setJavaPostCompilationEnable(boolean enable) {
this.enableJavaPostCompilation = enable;
}
/** Replies if the SARL compiler should be invoked before the Java compiler is invoked.
*
* @return {@code true} if the SARL compiler is invoked before the Java compiler.
* @since 0.12
*/
public boolean isSarlCompilationEnable() {
return this.enableSarlCompilation;
}
/** Set if the SARL compiler should be invoked before the Java compiler is invoked.
*
* @param enable is {@code true} if the SARL compiler is invoked before the Java compiler.
* @since 0.12
*/
public void setSarlCompilationEnable(boolean enable) {
this.enableSarlCompilation = enable;
}
/** Replies the formatter of the issue messages.
*
* @return the formatter.
*/
public IssueMessageFormatter getIssueMessageFormatter() {
return this.messageFormatter;
}
/** Set the formatter of the issue messages.
*
* @param formatter the formatter.
*/
public void setIssueMessageFormatter(IssueMessageFormatter formatter) {
this.messageFormatter = formatter;
}
/** Add a listener on the issue messages.
*
* @param listener the listener.
* @since 0.6
*/
public void addIssueMessageListener(IssueMessageListener listener) {
this.messageListeners.add(listener);
}
/** Add a listener on the issue messages.
*
* @param listener the listener.
* @since 0.6
*/
public void removeIssueMessageListener(IssueMessageListener listener) {
this.messageListeners.remove(listener);
}
/** Replies the message for the given issue.
*
* @param concreteSeverity the severity that was considered by the batch compiler. It may be stronger alert level that those in the {@code issue}.
* @param issue the issue.
* @param uri URI to the problem.
* @param message the formatted message.
* @since 0.6
*/
private void notifiesIssueMessageListeners(Severity concreteSeverity, Issue issue, org.eclipse.emf.common.util.URI uri, String message) {
for (final var listener : this.messageListeners) {
listener.onIssue(concreteSeverity, issue, uri, message);
}
}
/** Add a receiver on the successfully compiled resources.
*
* @param receiver the receiver.
* @since 0.6
*/
public void addCompiledResourceReceiver(ICompilatedResourceReceiver receiver) {
this.resourceReceivers.add(receiver);
}
/** Remove a receiver on the successfully compiled resources.
*
* @param receiver the receiver.
* @since 0.6
*/
public void removeCompiledResourceReceiver(ICompilatedResourceReceiver receiver) {
this.resourceReceivers.remove(receiver);
}
/** Replies the message for the given issue.
*
* @param resource the compiled resource.
* @since 0.6
*/
private void notifiesCompiledResourceReceiver(Resource resource) {
for (final var receiver : this.resourceReceivers) {
receiver.receiveCompiledResource(resource);
}
}
/** Replies the logger.
*
* @return the logger.
*/
public Logger getLogger() {
if (this.logger == null) {
this.logger = Logger.getLogger(getClass().getName());
}
return this.logger;
}
/** Set the logger.
*
* @param logger the logger.
*/
public void setLogger(Logger logger) {
this.logger = logger;
}
/** Set the provider of resource sets.
*
* @param resourceSetProvider the provider.
*/
@Inject
public void setResourceSetProvider(Provider resourceSetProvider) {
this.resourceSetProvider = resourceSetProvider;
}
private static File normalizeFile(String file) {
return new File(new File(file).getAbsoluteFile().toURI().normalize());
}
/** Replies if the trace files must be generated.
*
* A trace file contains the links between the class, java and SARL files.
* They are mandatory for retrieving and displaying the SARL source code from
* a JVM element.
*
*
The usual filename for the trace files follows the pattern
* {@code .Type.java._trace}, where {@code Type} is the name of the SARL type declaration.
*
* @return {@code true} for generation.
*/
public boolean isWriteTraceFiles() {
return this.writeTraceFiles;
}
/** Set if the trace files must be generated.
*
*
A trace file contains the links between the class, java and SARL files.
* They are mandatory for retreiving and displaying the SARL source code from
* a JVM element.
*
*
The usual filename for the trace files follows the pattern
* {@code .Type.java._trace}, where {@code Type} is the name of the SARL type declaration.
*
* @param writeTraceFiles {@code true} for generation.
*/
public void setWriteTraceFiles(boolean writeTraceFiles) {
this.writeTraceFiles = writeTraceFiles;
}
/** Replies if the storage files must be generated.
*
*
The storage files are binary versions of the resources in order
* to have faster reading/accessing.
*
*
The usual filename for the storage files follows the pattern
* {@code .Type.sarlbin}, where {@code Type} is the name of the SARL type declaration.
*
* @return {@code true} for generation.
*/
@Pure
public boolean isWriteStorageFiles() {
return this.writeStorageFiles;
}
/** Set if the storage files must be generated.
*
*
The storage files are binary versions of the resources in order
* to have faster reading/accessing.
*
*
The usual filename for the storage files follows the pattern
* {@code .Type.sarlbin}, where {@code Type} is the name of the SARL type declaration.
*
* @param writeStorageFiles {@code true} for generation.
*/
public void setWriteStorageFiles(boolean writeStorageFiles) {
this.writeStorageFiles = writeStorageFiles;
}
/** Replies if the compiler is verbose.
*
* @return {@code true} if the compiler is verbose.
*/
@Pure
public boolean isJavaCompilerVerbose() {
return this.verbose;
}
/** Set the underlying Java compiler verbosity.
*
* @param verbose {@code true} if the Java compiler is verbose.
*/
public void setJavaCompilerVerbose(boolean verbose) {
this.verbose = verbose;
}
/** Replies the current class loader.
*
* @return the class loader.
*/
@Pure
public ClassLoader getCurrentClassLoader() {
if (this.currentClassLoader == null) {
this.currentClassLoader = getClass().getClassLoader();
}
return this.currentClassLoader;
}
/** Set the current class loader.
*
* @param loader the new current class loader.
*/
public void setCurrentClassLoader(ClassLoader loader) {
this.currentClassLoader = null;
}
/** Set if the class loaderr of this batch compiler must be used as sthe parent class loader.
*
* @param useCurrentClassLoaderAsParent {@code true} for using the class loader of this batch compiler.
*/
public void setUseCurrentClassLoaderAsParent(boolean useCurrentClassLoaderAsParent) {
this.useCurrentClassLoaderAsParent = useCurrentClassLoaderAsParent;
}
/** Replies if the class loaderr of this batch compiler must be used as sthe parent class loader.
*
* @return {@code true} for using the class loader of this batch compiler.
*/
@Pure
public boolean isUseCurrentClassLoaderAsParent() {
return this.useCurrentClassLoaderAsParent;
}
/** Change the base path.
*
* @param basePath the base path.
*/
public void setBasePath(String basePath) {
setBaseURI(UriUtil.createFolderURI(normalizeFile(basePath)));
}
/** Change the base URI.
*
* @param basePath the base path.
*/
public void setBaseURI(org.eclipse.emf.common.util.URI basePath) {
this.baseUri = basePath;
}
/** Change the path where the Java files are generated.
*
* @param path the path, or {@code null} for using the default path in {@link SARLConfig#FOLDER_SOURCE_GENERATED}..
*/
public void setOutputPath(File path) {
this.outputPath = path;
}
/** Change the path where the Java files are generated.
*
* @param path the path.
*/
public void setOutputPath(String path) {
setOutputPath(normalizeFile(path));
}
/** Replies the path where the Java files are generated.
*
* @return the path; or {@code null} for using the default path in {@link SARLConfig#FOLDER_SOURCE_GENERATED}.
*/
@Pure
public File getOutputPath() {
return this.outputPath;
}
/** Replies the path where the class files are generated.
*
* @return the path; or {@code null} for ignoring the class generation.
*/
@Pure
public File getClassOutputPath() {
return this.classOutputPath;
}
/** Set the path where the class files are generated.
*
* @param path the path; or {@code null} for ignoring the class generation.
*/
@Pure
public void setClassOutputPath(File path) {
this.classOutputPath = path;
}
/** Change the classpath.
*
*
The classpath is a list the names of folders or jar files that are separated by {@link File#pathSeparator}.
*
* @param classpath the new classpath.
*/
public void setClassPath(String classpath) {
this.classpath = new ArrayList<>();
for (final var path : Strings.split(classpath, File.pathSeparator)) {
this.classpath.add(normalizeFile(path));
}
}
/** Change the classpath.
*
* @param classpath the new classpath.
*/
public void setClassPath(Collection classpath) {
this.classpath = new ArrayList<>(classpath);
}
/** Replies the classpath.
*
* @return the classpath.
*/
@Pure
public List getClassPath() {
if (this.classpath == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(this.classpath);
}
/** Change the module-path.
* This function does nothing if the current version of Java is not supporting modules.
*
* The module-path is a list the names of folders or jar files that are separated by {@link File#pathSeparator}.
*
* @param modulepath the new module-path.
* @since 0.12
*/
public void setModulePath(String modulepath) {
this.modulepath = new ArrayList<>();
for (final var path : Strings.split(modulepath, File.pathSeparator)) {
this.modulepath.add(normalizeFile(path));
}
}
/** Change the module-path.
* This function does nothing if the current version of Java is not supporting modules.
*
* @param modulepath the new module-path.
* @since 0.12
*/
public void setModulePath(Collection modulepath) {
this.modulepath = new ArrayList<>(modulepath);
}
/** Replies the module-path.
* This function replies the empty list if the current version of Java is not supporting modules.
*
* @return the module-path.
* @since 0.12
*/
@Pure
public List getModulePath() {
if (this.modulepath == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(this.modulepath);
}
/** Change the path where the Xtext stubs are generated.
*
* @param path the path.
*/
public void setTempDirectory(File path) {
this.tempPath = path;
}
/** Change the path where the Xtext stubs are generated.
*
* @param path the path.
*/
public void setTempDirectory(String path) {
setTempDirectory(normalizeFile(path));
}
/** Replies the path where the Xtext stubs are generated.
*
* @return the path; or {@code null} for using the default path.
*/
@Pure
public File getTempDirectory() {
if (this.tempPath == null) {
this.tempPath = createTempDirectory();
}
return this.tempPath;
}
/** Create the temp directory that should be used by the compiler.
*
* @return the temp directory, never {@code null}.
*/
@SuppressWarnings("static-method")
protected File createTempDirectory() {
final var tmpPath = new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
var i = 0;
var tmp = new File(tmpPath, "sarlc" + i); //$NON-NLS-1$
while (tmp.exists()) {
++i;
tmp = new File(tmpPath, "sarlc" + i); //$NON-NLS-1$
}
return tmp;
}
/** Replies the cleaning policy that is applied by this batch compiler.
*
* @return the cleaning policy, never {@code null}.
* @since 0.10
*/
@Pure
public CleaningPolicy getCleaningPolicy() {
return this.cleaningPolicy;
}
/** Change the cleaning policy that is applied by this batch compiler.
*
* @param policy the cleaning policy. If it is {@code null}, the
* {@link CleaningPolicy#getDefault() default policy} is used.
* @since 0.10
*/
public void setCleaningPolicy(CleaningPolicy policy) {
this.cleaningPolicy = policy == null ? CleaningPolicy.getDefault() : policy;
}
/** Replies if the temp folder must be deleted at the end of the compilation.
*
* @return {@code true} if the temp folder is deleted.
* @deprecated since 0.10, see {@link #getCleaningPolicy()}.
*/
@Pure
@Deprecated(forRemoval = true, since = "0.10")
@Inline(value = "getCleaningPolicy() != $1.NO_CLEANING", imported = {CleaningPolicy.class})
public boolean isDeleteTempDirectory() {
return getCleaningPolicy() != CleaningPolicy.NO_CLEANING;
}
/** Set if the temp folder must be deleted at the end of the compilation.
*
* @param delete {@code true} if the temp folder is deleted.
* @deprecated since 0.10, see {@link #setCleaningPolicy(CleaningPolicy)}.
*/
@Deprecated(forRemoval = true, since = "0.10")
@Inline(value = "setCleaningPolicy(($1) ? $2.INTERNAL_CLEANING : $2.NO_CLEANING)", imported = {CleaningPolicy.class})
public void setDeleteTempDirectory(boolean delete) {
setCleaningPolicy(delete ? CleaningPolicy.INTERNAL_CLEANING : CleaningPolicy.NO_CLEANING);
}
/** Change the file encoding.
*
* @param encoding the encoding, usually {@code UTF-8}.
*/
public void setFileEncoding(String encoding) {
this.encoding = encoding;
}
/** Change the file encoding.
*
* @return the file encoding, or {@code null} if the default encoding must be used.
*/
@Pure
public String getFileEncoding() {
return this.encoding;
}
/** Replies the current generator config.
*
* @return the generator config.
*/
protected GeneratorConfig getGeneratorConfig() {
if (this.currentGeneratorConfiguration == null) {
this.currentGeneratorConfiguration = this.generatorConfigProvider.get(null);
}
return this.currentGeneratorConfiguration;
}
/** Replies the current generator config v2.
*
* @return the generator config v2.
*/
protected GeneratorConfig2 getGeneratorConfig2() {
if (this.currentGeneratorConfiguration2 == null) {
this.currentGeneratorConfiguration2 = this.generatorConfigProvider2.get(null);
}
return this.currentGeneratorConfiguration2;
}
/** Change the version of the Java source to be used for the generated Java files.
*
* @param version the Java version.
*/
public void setJavaSourceVersion(String version) {
final var javaVersion = JavaVersion.fromQualifier(version);
if (javaVersion == null) {
final var qualifiers = new ArrayList();
for (final var vers : JavaVersion.values()) {
qualifiers.addAll(vers.getAllQualifiers());
}
throw new RuntimeException(MessageFormat.format(
Messages.SarlBatchCompiler_0, version, Joiner.on(Messages.SarlBatchCompiler_1).join(qualifiers)));
}
getGeneratorConfig().setJavaSourceVersion(javaVersion);
}
/** Replies the version of the Java source to be used for the generated Java files.
*
* @return the Java version.
*/
@Pure
public String getJavaSourceVersion() {
return getGeneratorConfig().getJavaSourceVersion().getQualifier();
}
/** Replies if the current project is modular.
* A project is module when it defines the "module-info.java" file.
*
* @return {@code true} if the project is detected as modular.
* @since 0.12
*/
@Pure
public boolean isModularProject() {
for (final var folder : getSourcePaths()) {
final var infoFile = new File(folder, "module-info.java"); //$NON-NLS-1$
if (infoFile.isFile()) {
return true;
}
}
return false;
}
/** Replies the compiler generate the Xbase expressions.
*
* @return {@code true} if the compiler generates the expressions
*/
@Pure
public boolean isGenerateExpressions() {
return getGeneratorConfig().isGenerateExpressions();
}
/** Set if the compiler generate the Xbase expressions.
*
* @param generateExpressions {@code true} if the compiler generates the expressions
*/
public void setGenerateExpressions(boolean generateExpressions) {
getGeneratorConfig().setGenerateExpressions(generateExpressions);
}
/** Replies the {@code @SuppressWarnings} is generated.
*
* @return {@code true} if the compiler generates the warning supression annotations.
*/
@Pure
public boolean isGenerateSyntheticSuppressWarnings() {
return getGeneratorConfig().isGenerateSyntheticSuppressWarnings();
}
/** Set if the {@code @SuppressWarnings} is generated.
*
* @param generateAnnotations {@code true} if the compiler generates the warning supression annotations.
*/
public void setGenerateSyntheticSuppressWarnings(boolean generateAnnotations) {
getGeneratorConfig().setGenerateSyntheticSuppressWarnings(generateAnnotations);
}
/** Replies the {@code @Generated} is generated.
*
* @return {@code true} if the compiler generates the generated annotations.
*/
@Pure
public boolean isGenerateGeneratedAnnotation() {
return getGeneratorConfig().isGenerateGeneratedAnnotation();
}
/** Set if the {@code @Generated} is generated.
*
* @param generateAnnotations {@code true} if the compiler generates the generated annotations.
*/
public void setGenerateGeneratedAnnotation(boolean generateAnnotations) {
getGeneratorConfig().setGenerateGeneratedAnnotation(generateAnnotations);
}
/** Replies if the generation date is included in the {@code @Generated} annotations.
*
* @return {@code true} if the generation date is added.
*/
@Pure
public boolean isIncludeDateInGeneratedAnnotation() {
return getGeneratorConfig().isIncludeDateInGeneratedAnnotation();
}
/** Set if the generation date is included in the {@code @Generated} annotations.
*
* @param includeDateInGeneratedAnnotation {@code true} if the generation date is added.
*/
public void setIncludeDateInGeneratedAnnotation(boolean includeDateInGeneratedAnnotation) {
getGeneratorConfig().setIncludeDateInGeneratedAnnotation(includeDateInGeneratedAnnotation);
}
/** Replies the comment in the {@code @Generated} annnotations.
*
* @return the comment.
*/
@Pure
public String getGeneratedAnnotationComment() {
return getGeneratorConfig().getGeneratedAnnotationComment();
}
/** Set the comment in the {@code @Generated} annnotations.
*
* @param comment the comment.
*/
public void setGeneratedAnnotationComment(String comment) {
getGeneratorConfig().setGeneratedAnnotationComment(comment);
}
/** Replies if the {@code @Inline} shall be generated.
*
* @return {@code true} if annotation shall be generated.
*/
@Pure
public boolean isGenerateInlineAnnotation() {
return getGeneratorConfig2().isGenerateInlineAnnotation();
}
/** Set if the {@code @Inline} shall be generated.
*
* @param generateInlineAnnotation {@code true} if annotation shall be generated.
*/
public void setGenerateInlineAnnotation(final boolean generateInlineAnnotation) {
getGeneratorConfig2().setGenerateInlineAnnotation(generateInlineAnnotation);
}
/** Replies if constant expression interpreter shall be called for generated {@code @Inline}.
*
* @return {@code true} if annotation shall be generated.
*/
@Pure
public boolean isUseExpressionInterpreterForInlineAnnotation() {
return getGeneratorConfig2().isUseExpressionInterpreterForInlineAnnotation();
}
/** Set if the constant expression interpreter shall be called for generated {@code @Inline}.
*
* @param generateInlineAnnotation {@code true} if annotation shall be generated.
*/
public void setUseExpressionInterpreterForInlineAnnotation(final boolean generateInlineAnnotation) {
getGeneratorConfig2().setUseExpressionInterpreterForInlineAnnotation(generateInlineAnnotation);
}
/** Replies if the {@code @Pure} shall be generated.
*
* @return {@code true} if annotation shall be generated.
*/
@Pure
public boolean isGeneratePureAnnotation() {
return getGeneratorConfig2().isGeneratePureAnnotation();
}
/** Set if the {@code @Pure} shall be generated.
*
* @param generatePureAnnotation {@code true} if annotation shall be generated.
*/
public void setGeneratePureAnnotation(final boolean generatePureAnnotation) {
getGeneratorConfig2().setGeneratePureAnnotation(generatePureAnnotation);
}
/** Replies if the equality test functions shall be generated.
*
* @return {@code true} if the functions shall be generated.
* @since 0.8
*/
@Pure
public boolean isGenerateEqualityTestFunctions() {
return getGeneratorConfig2().isGenerateEqualityTestFunctions();
}
/** Set if the equality test functions shall be generated.
*
* @param generateFunctions {@code true} if the functions shall be generated.
* @since 0.8
*/
public void setGenerateEqualityTestFunctions(final boolean generateFunctions) {
getGeneratorConfig2().setGenerateEqualityTestFunctions(generateFunctions);
}
/** Replies if the toString functions shall be generated.
*
* @return {@code true} if the functions shall be generated.
* @since 0.8
*/
@Pure
public boolean isGenerateToStringFunctions() {
return getGeneratorConfig2().isGenerateToStringFunctions();
}
/** Set if the toString functions shall be generated.
*
* @param generateFunctions {@code true} if the functions shall be generated.
* @since 0.8
*/
public void setGenerateToStringFunctions(final boolean generateFunctions) {
getGeneratorConfig2().setGenerateToStringFunctions(generateFunctions);
}
/** Replies if the clone functions shall be generated.
*
* @return {@code true} if the functions shall be generated.
* @since 0.8
*/
@Pure
public boolean isGenerateCloneFunctions() {
return getGeneratorConfig2().isGenerateCloneFunctions();
}
/** Set if the clone functions shall be generated.
*
* @param generateFunctions {@code true} if the functions shall be generated.
* @since 0.8
*/
public void setGenerateCloneFunctions(final boolean generateFunctions) {
getGeneratorConfig2().setGenerateCloneFunctions(generateFunctions);
}
/** Replies if the serial number fields shall be generated.
*
* @return {@code true} if the fields shall be generated.
* @since 0.8
*/
@Pure
public boolean isGenerateSerialNumberFields() {
return getGeneratorConfig2().isGenerateSerialNumberFields();
}
/** Set if the serial number fields shall be generated.
*
* @param generateFields {@code true} if the fields shall be generated.
* @since 0.8
*/
public void setGenerateSerialNumberFields(final boolean generateFields) {
getGeneratorConfig2().setGenerateSerialNumberFields(generateFields);
}
/** Change the source path.
*
* The source path is a list the names of folders that are separated by {@link File#pathSeparator}.
*
* @param sourcePath the new source path.
*/
public void setSourcePath(String sourcePath) {
this.sourcePath = new ArrayList<>();
for (final var path : Strings.split(sourcePath, File.pathSeparator)) {
this.sourcePath.add(normalizeFile(path));
}
}
/** Change the source path.
*
* @param sourcePath the new source path.
*/
public void setSourcePath(Collection sourcePath) {
this.sourcePath = new ArrayList<>(sourcePath);
}
/** Add a folder to the source path.
*
* @param sourcePath the new source path.
*/
public void addSourcePath(String sourcePath) {
if (!Strings.isEmpty(sourcePath)) {
addSourcePath(normalizeFile(sourcePath));
}
}
/** Add a folder to the source path.
*
* @param sourcePath the new source path.
*/
public void addSourcePath(File sourcePath) {
if (this.sourcePath == null) {
this.sourcePath = new ArrayList<>();
}
this.sourcePath.add(sourcePath);
}
/** Replies the source path.
*
* @return the source path.
*/
@Pure
public List getSourcePaths() {
if (this.sourcePath == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(this.sourcePath);
}
private List getSourcePathStrings() {
if (this.sourcePath == null) {
return Collections.emptyList();
}
final var list = new ArrayList(this.sourcePath.size());
for (final var input : this.sourcePath) {
list.add(input.getAbsolutePath());
}
return list;
}
private void configureExtraLanguageGenerators() {
final var generators = getExtraLanguageGenerators();
if (Strings.isEmpty(generators)) {
this.extraLanguageContributions.setContributionChecker(DISABLER);
} else {
final var identifiers = generators.split("\\s*" + Pattern.quote(File.pathSeparator) + "\\s*"); //$NON-NLS-1$ //$NON-NLS-2$
this.extraLanguageContributions.setContributionChecker(it -> {
for (final var id : identifiers) {
if (it.isAcceptedIdentifier(id)) {
return true;
}
}
return false;
});
}
}
private void unconfigureExtraLanguageGenerators() {
this.extraLanguageContributions.setContributionChecker(null);
}
/** Run the compilation.
*
* @return success status.
*/
@Inline(value = "compile(($1) null)", imported = {IProgressMonitor.class})
public boolean compile() {
return compile((IProgressMonitor) null);
}
/** Run the compilation.
*
* @param cancel is the tool for canceling the compilation.
* @return success status.
*/
public boolean compile(CancelIndicator cancel) {
return compile(cancel != null ? new CancelIndicatorProgressMonitor(cancel) : null);
}
/** Run the compilation.
*
* @param progress monitor of the progress of the compilation.
* @return success status.
* @since 0.8
*/
public boolean compile(IProgressMonitor progress) {
final var monitor = progress == null ? new NullProgressMonitor() : progress;
try {
monitor.beginTask(Messages.SarlBatchCompiler_42, 18);
if (!checkConfiguration(monitor)) {
return false;
}
monitor.worked(1);
final var resourceSet = this.resourceSetProvider.get();
configureExtraLanguageGenerators();
if (!configureWorkspace(resourceSet, monitor)) {
return false;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(Utils.dump(getGeneratorConfig(), false));
}
monitor.worked(2);
monitor.subTask(Messages.SarlBatchCompiler_43);
if (this.generatorConfigProvider instanceof GeneratorConfigProvider igen) {
igen.install(resourceSet, getGeneratorConfig());
}
if (monitor.isCanceled()) {
return false;
}
if (this.generatorConfigProvider2 instanceof GeneratorConfigProvider2 igen) {
igen.install(resourceSet, getGeneratorConfig2());
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(Utils.dump(getGeneratorConfig2(), false));
}
if (monitor.isCanceled()) {
return false;
}
monitor.worked(3);
monitor.subTask(Messages.SarlBatchCompiler_44);
final var stubClassDirectory = createTempDir(BINCLASS_FOLDER_PREFIX);
if (monitor.isCanceled()) {
return false;
}
if (isSarlCompilationEnable()) {
monitor.worked(4);
try {
monitor.subTask(Messages.SarlBatchCompiler_45);
this.compilerPhases.setIndexing(resourceSet, true);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(5);
// install a type provider without index lookup for the first phase
installJvmTypeProvider(resourceSet, stubClassDirectory, true, monitor);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(6);
loadSARLFiles(resourceSet, monitor);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(7);
final var stubSourceDirectory = createStubs(resourceSet, monitor);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(8);
var compilerStatus = preCompileStubs(stubSourceDirectory, stubClassDirectory, monitor);
if (!compilerStatus.isSuccess() && compilerStatus != CompilerStatus.NOTHING_TO_COMPILE) {
if (compilerStatus != CompilerStatus.CANCELED) {
reportInternalError(MessageFormat.format(Messages.SarlBatchCompiler_2, compilerStatus.getFailureExplanation()));
}
return false;
}
monitor.worked(9);
compilerStatus = preCompileJava(stubSourceDirectory, stubClassDirectory, monitor);
if (!compilerStatus.isSuccess() && compilerStatus != CompilerStatus.NOTHING_TO_COMPILE) {
if (compilerStatus == CompilerStatus.CANCELED) {
return false;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_3, compilerStatus.getFailureExplanation()));
}
}
monitor.worked(10);
} finally {
monitor.subTask(Messages.SarlBatchCompiler_46);
this.compilerPhases.setIndexing(resourceSet, false);
if (monitor.isCanceled()) {
return false;
}
}
monitor.worked(11);
// install a fresh type provider for the second phase, so we clear all previously cached classes and misses.
installJvmTypeProvider(resourceSet, stubClassDirectory, false, monitor);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(12);
generateJvmElements(resourceSet, monitor);
if (monitor.isCanceled()) {
return false;
}
monitor.worked(13);
final var validatedResources = new ArrayList();
final var issues = validate(resourceSet, validatedResources, monitor);
if (monitor.isCanceled()) {
return false;
}
if (!issues.isEmpty()) {
if (reportCompilationIssues(issues)) {
return false;
}
}
monitor.worked(14);
overrideXtextInternalLoggers();
generateJavaFiles(validatedResources, monitor);
if (monitor.isCanceled()) {
return false;
}
}
monitor.worked(15);
if (isJavaPostCompilationEnable()) {
final var compilerStatus = postCompileJava(monitor);
if (!compilerStatus.isSuccess() && compilerStatus != CompilerStatus.NOTHING_TO_COMPILE) {
if (compilerStatus != CompilerStatus.CANCELED) {
reportInternalError(MessageFormat.format(Messages.SarlBatchCompiler_2, compilerStatus.getFailureExplanation()));
}
return false;
}
} else {
reportInternalWarning(Messages.SarlBatchCompiler_65);
}
monitor.worked(16);
} finally {
finalizationStage(monitor);
monitor.done();
}
return true;
}
private void finalizationStage(IProgressMonitor monitor) {
monitor.subTask(Messages.SarlBatchCompiler_47);
destroyClassLoader(this.jvmTypesClassLoader);
destroyClassLoader(this.annotationProcessingClassLoader);
switch (getCleaningPolicy()) {
case FULL_CLEANING:
if (this.tempPath != null) {
cleanFolder(this.tempPath, null);
}
break;
case NO_CLEANING:
// Do nothing
break;
case INTERNAL_CLEANING:
monitor.subTask(Messages.SarlBatchCompiler_48);
for (final File file : this.tempFolders) {
cleanFolder(file, null);
}
break;
default:
// This case should never occur
throw new IllegalStateException();
}
this.tempPath = null;
this.tempFolders.clear();
//
unconfigureExtraLanguageGenerators();
}
/** Change the loggers that are internally used by Xtext.
*/
protected void overrideXtextInternalLoggers() {
final var logger = getLogger();
final var factory = new InternalXtextLoggerFactory(logger);
final var internalLogger = org.apache.log4j.Logger.getLogger(
MessageFormat.format(Messages.SarlBatchCompiler_40, logger.getName()), factory);
final var lr = new LoggerRepositoryWrapper(LogManager.getLoggerRepository());
lr.registerWrapper("org.eclipse.xtext.xbase.resource.BatchLinkableResourceStorageWritable", internalLogger); //$NON-NLS-1$
lr.registerWrapper("org.eclipse.xtext.xbase.resource.BatchLinkableResource", internalLogger); //$NON-NLS-1$
lr.registerWrapper("org.eclipse.xtend.core.macro.ProcessorInstanceForJvmTypeProvider", internalLogger); //$NON-NLS-1$
LogManager.setRepositorySelector(() -> lr, SarlBatchCompiler.class);
}
/** Create a message for the issue.
*
* @param severity the severity that is considered by the compiler. It may be stronger than the one specified in the issue.
* @param issue the issue.
* @return the message.
*/
protected String createIssueMessage(Severity severity, Issue issue) {
final var formatter = getIssueMessageFormatter();
final var uriToProblem = issue.getUriToProblem();
if (formatter != null) {
final var message = formatter.format(severity, issue, uriToProblem);
if (message != null) {
return message;
}
}
if (uriToProblem != null) {
final var resourceUri = uriToProblem.trimFragment();
return MessageFormat.format(Messages.SarlBatchCompiler_4,
severity, resourceUri.lastSegment(),
resourceUri.isFile() ? resourceUri.toFileString() : "", //$NON-NLS-1$
issue.getLineNumber(), issue.getColumn(), issue.getCode(), issue.getMessage());
}
return MessageFormat.format(Messages.SarlBatchCompiler_5,
severity, issue.getLineNumber(), issue.getColumn(), issue.getCode(), issue.getMessage());
}
/** Output the given issues that result from the compilation of the SARL code.
*
* @param issues the issues to report.
* @return {@code true} if at least one error was reported, {@code false} if
* no error was reported.
*/
protected boolean reportCompilationIssues(Iterable issues) {
var hasError = false;
for (final var issue : issues) {
final Severity concreteSeverity;
final String issueMessage;
switch (issue.getSeverity()) {
case ERROR:
hasError = true;
concreteSeverity = Severity.ERROR;
issueMessage = createIssueMessage(concreteSeverity, issue);
getLogger().severe(issueMessage);
break;
case WARNING:
if (getReportWarningsAsErrors()) {
hasError = true;
concreteSeverity = Severity.ERROR;
issueMessage = createIssueMessage(concreteSeverity, issue);
getLogger().severe(issueMessage);
} else {
concreteSeverity = Severity.WARNING;
issueMessage = createIssueMessage(concreteSeverity, issue);
getLogger().warning(issueMessage);
}
break;
case INFO:
concreteSeverity = Severity.INFO;
issueMessage = createIssueMessage(concreteSeverity, issue);
getLogger().info(issueMessage);
break;
case IGNORE:
default:
concreteSeverity = Severity.IGNORE;
issueMessage = createIssueMessage(concreteSeverity, issue);
break;
}
notifiesIssueMessageListeners(concreteSeverity, issue, issue.getUriToProblem(), issueMessage);
}
return hasError;
}
/** Reports the given warning message.
*
* @param message the warning message.
* @since 0.8
*/
protected void reportInternalWarning(String message) {
getLogger().warning(message);
if (getReportInternalProblemsAsIssues()) {
final org.eclipse.emf.common.util.URI uri = null;
final var issue = new Issue.IssueImpl();
issue.setCode(INTERNAL_ERROR_CODE);
issue.setMessage(message);
issue.setUriToProblem(uri);
issue.setSeverity(Severity.WARNING);
notifiesIssueMessageListeners(
getReportWarningsAsErrors() ? Severity.ERROR : Severity.WARNING,
issue, uri, message);
}
}
/** Reports the given warning message.
*
* @param message the warning message.
* @param exception the source of the exception.
* @since 0.8
*/
protected void reportInternalWarning(String message, Throwable exception) {
getLogger().log(Level.WARNING, message, exception);
if (getReportInternalProblemsAsIssues()) {
final org.eclipse.emf.common.util.URI uri = null;
final var issue = new Issue.IssueImpl();
issue.setCode(INTERNAL_ERROR_CODE);
issue.setMessage(message);
issue.setUriToProblem(uri);
issue.setSeverity(Severity.WARNING);
notifiesIssueMessageListeners(
getReportWarningsAsErrors() ? Severity.ERROR : Severity.WARNING,
issue, uri, message);
}
}
/** Reports the given error message.
*
* @param message the error message.
* @param exception the source of the exception.
* @since 0.8
*/
protected void reportInternalError(String message, Throwable exception) {
getLogger().log(Level.SEVERE, message, exception);
if (getReportInternalProblemsAsIssues()) {
final org.eclipse.emf.common.util.URI uri = null;
final var issue = new Issue.IssueImpl();
issue.setCode(INTERNAL_ERROR_CODE);
issue.setMessage(message);
issue.setUriToProblem(uri);
issue.setSeverity(Severity.ERROR);
notifiesIssueMessageListeners(Severity.ERROR, issue, uri, message);
}
}
/** Reports the given error message.
*
* @param message the error message.
* @param parameters the values of the parameters that must be dynamically replaced within the message text.
* @since 0.8
*/
protected void reportInternalError(String message, Object... parameters) {
String msg;
Throwable error = null;
if (parameters == null || parameters.length <= 0) {
msg = message;
} else {
try {
msg = MessageFormat.format(message, parameters);
} catch (Throwable exception) {
msg = message;
error = exception;
}
}
if (error != null) {
getLogger().log(Level.SEVERE, msg, error);
} else {
getLogger().severe(msg);
}
if (getReportInternalProblemsAsIssues()) {
final org.eclipse.emf.common.util.URI uri = null;
final var issue = new Issue.IssueImpl();
issue.setCode(INTERNAL_ERROR_CODE);
issue.setMessage(msg);
issue.setUriToProblem(uri);
issue.setSeverity(Severity.ERROR);
notifiesIssueMessageListeners(Severity.ERROR, issue, uri, message);
}
}
/** Reports the given information message.
*
* @param message the information message.
* @param parameters the values of the parameters that must be dynamically replaced within the message text.
* @since 0.12
*/
protected void reportInternalInfo(String message, Object... parameters) {
getLogger().info(MessageFormat.format(message, parameters));
}
/** Generate the Java files from the SARL scripts.
*
* @param validatedResources the validatedResources for which the Java files could be generated.
* @param progress monitor of the progress of the compilation.
*/
protected void generateJavaFiles(Iterable validatedResources, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_49);
getLogger().info(MessageFormat.format(Messages.SarlBatchCompiler_28, getOutputPath()));
final var javaIoFileSystemAccess = this.javaIoFileSystemAccessProvider.get();
javaIoFileSystemAccess.setOutputConfigurations(this.outputConfigurations);
// The function configureWorkspace should set the output paths with absolute paths.
//javaIoFileSystemAccess.setOutputPath(getOutputPath().getAbsolutePath());
javaIoFileSystemAccess.setWriteTrace(isWriteTraceFiles());
if (progress.isCanceled()) {
return;
}
final var context = new GeneratorContext();
context.setCancelIndicator(() -> progress.isCanceled());
for (final var resource : validatedResources) {
if (progress.isCanceled()) {
return;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_23, resource.getURI().lastSegment()));
}
if (isWriteStorageFiles() && resource instanceof StorageAwareResource storageAwareResource) {
storageAwareResource.getResourceStorageFacade().saveResource(storageAwareResource, javaIoFileSystemAccess);
}
if (progress.isCanceled()) {
return;
}
this.generator.generate(resource, javaIoFileSystemAccess, context);
notifiesCompiledResourceReceiver(resource);
}
}
/** Generate the JVM model elements.
*
* @param progress monitor of the progress of the compilation.
* @param resourceSet the container of the scripts.
*/
protected void generateJvmElements(ResourceSet resourceSet, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_21);
getLogger().info(Messages.SarlBatchCompiler_21);
final var originalResources = resourceSet.getResources();
final var toBeResolved = new ArrayList(originalResources.size());
for (final var resource : originalResources) {
if (progress.isCanceled()) {
return;
}
if (isSourceFile(resource)) {
toBeResolved.add(resource);
}
}
for (final var resource : toBeResolved) {
if (progress.isCanceled()) {
return;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_26, resource.getURI().lastSegment()));
}
EcoreUtil.resolveAll(resource);
EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl);
}
}
/** Generate the JVM model elements, and validate generated elements.
*
* @param resourceSet the container of the scripts.
* @param validResources will be filled by this function with the collection of resources that was successfully validated.
* @param progress monitor of the progress of the compilation.
* @return the list of the issues.
*/
protected List validate(ResourceSet resourceSet, Collection validResources, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_38);
getLogger().info(Messages.SarlBatchCompiler_38);
final var resources = new LinkedList<>(resourceSet.getResources());
final var issuesToReturn = new ArrayList();
for (final var resource : resources) {
if (progress.isCanceled()) {
return issuesToReturn;
}
if (isSourceFile(resource)) {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_22, resource.getURI().lastSegment()));
}
final var resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE
.getResourceServiceProvider(resource.getURI());
if (resourceServiceProvider != null) {
final var resourceValidator = resourceServiceProvider.getResourceValidator();
final var result = resourceValidator.validate(resource, CheckMode.ALL, null);
if (progress.isCanceled()) {
return issuesToReturn;
}
final var issues = new TreeSet<>(getIssueComparator());
boolean hasValidationError = false;
for (final var issue : result) {
if (progress.isCanceled()) {
return issuesToReturn;
}
if (issue.isSyntaxError() || issue.getSeverity() == Severity.ERROR) {
hasValidationError = true;
}
issues.add(issue);
}
if (!hasValidationError) {
if (!issues.isEmpty()) {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_39, resource.getURI().lastSegment()));
}
issuesToReturn.addAll(issues);
}
validResources.add(resource);
} else {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_39, resource.getURI().lastSegment()));
}
issuesToReturn.addAll(issues);
}
}
}
}
return issuesToReturn;
}
/** Replies if the given resource is a script.
*
* @param resource the resource to test.
* @return {@code true} if the given resource is a script.
*/
@SuppressWarnings("static-method")
protected boolean isSourceFile(Resource resource) {
if (resource instanceof BatchLinkableResource bres) {
return !bres.isLoadedFromStorage();
}
return false;
}
/** Compile the stub files before the compilation of the project's files.
*
* @param sourceDirectory the source directory where stubs are stored.
* @param classDirectory the output directory, where stub binary files should be generated.
* @param progress monitor of the progress of the compilation.
* @return the success status.
*/
protected CompilerStatus preCompileStubs(File sourceDirectory, File classDirectory, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_50);
return runJavaCompiler(classDirectory, Collections.singletonList(sourceDirectory), getClassPath(),
getModulePath(), true, false, progress);
}
/** Compile the java files before the compilation of the project's files.
*
* @param sourceDirectory the source directory where java files are stored.
* @param classDirectory the output directory, where binary files should be generated.
* @param progress monitor of the progress of the compilation.
* @return the success status.
*/
protected CompilerStatus preCompileJava(File sourceDirectory, File classDirectory, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_51);
final var cp = Iterables.concat(Collections.singleton(sourceDirectory), getClassPath());
final var mp = Collections.emptyList();
return runJavaCompiler(classDirectory, getSourcePaths(),
cp, mp,
false, false, progress);
}
/** Compile the java files after the compilation of the project's files.
*
* @param progress monitor of the progress of the compilation.
* @return the success status.
*/
protected CompilerStatus postCompileJava(IProgressMonitor progress) {
assert progress != null;
final var msg = MessageFormat.format(Messages.SarlBatchCompiler_25, getJavaCompiler().getName());
progress.subTask(msg);
getLogger().info(msg);
final var classOutputPath = getClassOutputPath();
if (classOutputPath == null) {
getLogger().info(Messages.SarlBatchCompiler_24);
return CompilerStatus.COMPILATION_SUCCESS;
}
final var sources = Iterables.concat(getSourcePaths(), Collections.singleton(getOutputPath()));
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_29, toPathString(sources)));
}
final var classpath = getClassPath();
final var modulepath = getModulePath();
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_64, toPathString(classpath), toPathString(modulepath)));
}
return runJavaCompiler(classOutputPath, sources, classpath, modulepath, true, true, progress);
}
private static String toPathString(Iterable files) {
final var result = new StringBuilder();
for (final File file : files) {
if (result.length() > 0) {
result.append(File.pathSeparator);
}
result.append(file.toString());
}
return result.toString();
}
/** Run the Java compiler.
*
* @param classDirectory the output directory.
* @param sourcePathDirectories the source directories.
* @param classPathEntries classpath entries.
* @param modulePathEntries classpath entries.
* @param enableCompilerOutput indicates if the Java compiler output is displayed.
* @param enableOptimization indicates if the Java compiler must applied optimization flags.
* @param progress monitor of the progress of the compilation.
* @return the success status.
* @see IJavaBatchCompiler
*/
@SuppressWarnings({ "resource" })
protected CompilerStatus runJavaCompiler(File classDirectory, Iterable sourcePathDirectories,
Iterable classPathEntries, Iterable modulePathEntries, boolean enableCompilerOutput,
boolean enableOptimization, IProgressMonitor progress) {
var encoding = this.encodingProvider.getDefaultEncoding();
if (Strings.isEmpty(encoding)) {
encoding = null;
}
if (progress.isCanceled()) {
return CompilerStatus.CANCELED;
}
final PrintWriter outWriter;
final PrintWriter errWriter;
if (enableCompilerOutput) {
outWriter = getInfoCompilerOutputWriter();
errWriter = getErrorCompilerOutputWriter();
} else {
outWriter = getDebugCompilerOutputWriter();
errWriter = getDebugCompilerOutputWriter();
}
if (progress.isCanceled()) {
return CompilerStatus.CANCELED;
}
return getJavaCompiler().compile(
classDirectory,
sourcePathDirectories,
classPathEntries,
modulePathEntries,
getJavaSourceVersion(),
encoding,
isJavaCompilerVerbose(),
enableOptimization ? getOptimizationLevel() : null,
outWriter,
errWriter,
getLogger(),
progress);
}
private PrintWriter getDebugCompilerOutputWriter() {
final var debugWriter = new Writer() {
@Override
public void write(char[] data, int offset, int count) throws IOException {
if (getLogger().isLoggable(Level.FINEST)) {
final var message = String.copyValueOf(data, offset, count);
getLogger().finest(message);
}
}
@Override
public void flush() throws IOException {
//
}
@Override
public void close() throws IOException {
//
}
};
return new PrintWriter(debugWriter);
}
private PrintWriter getErrorCompilerOutputWriter() {
final var debugWriter = new Writer() {
@Override
public void write(char[] data, int offset, int count) throws IOException {
final var message = String.copyValueOf(data, offset, count);
reportInternalError(message);
}
@Override
public void flush() throws IOException {
//
}
@Override
public void close() throws IOException {
//
}
};
return new PrintWriter(debugWriter);
}
private PrintWriter getInfoCompilerOutputWriter() {
final var debugWriter = new Writer() {
@Override
public void write(char[] data, int offset, int count) throws IOException {
final var message = String.copyValueOf(data, offset, count);
reportInternalInfo(message);
}
@Override
public void flush() throws IOException {
//
}
@Override
public void close() throws IOException {
//
}
};
return new PrintWriter(debugWriter);
}
/** Create the stubs.
*
* @param resourceSet the input resource set.
* @param progress monitor of the progress of the compilation.
* @return the folder in which the stubs are located. Replies {@code null} if the activity is canceled.
*/
protected File createStubs(ResourceSet resourceSet, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_53);
final var outputDirectory = createTempDir(STUB_FOLDER_PREFIX);
if (progress.isCanceled()) {
return null;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_19, outputDirectory));
}
final var fileSystemAccess = this.javaIoFileSystemAccessProvider.get();
if (progress.isCanceled()) {
return null;
}
fileSystemAccess.setOutputPath(outputDirectory.toString());
final var resources = new ArrayList<>(resourceSet.getResources());
for (final var resource : resources) {
if (progress.isCanceled()) {
return null;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_20, resource.getURI()));
}
final var description = this.resourceDescriptionManager.getResourceDescription(resource);
this.stubGenerator.doGenerateStubs(fileSystemAccess, description);
}
return outputDirectory;
}
/** Load the SARL files in the given resource set.
*
* @param progress monitor of the progress of the compilation.
* @param resourceSet the resource set to load from.
*/
protected void loadSARLFiles(ResourceSet resourceSet, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_54);
this.encodingProvider.setDefaultEncoding(getFileEncoding());
final var nameBasedFilter = new NameBasedFilter();
nameBasedFilter.setExtension(this.fileExtensionProvider.getPrimaryFileExtension());
final var pathTraverser = new PathTraverser();
final var sourcePathDirectories = getSourcePathStrings();
if (progress.isCanceled()) {
return;
}
final var pathes = pathTraverser.resolvePathes(sourcePathDirectories,
input -> nameBasedFilter.matches(input));
if (progress.isCanceled()) {
return;
}
for (final var source : pathes.keySet()) {
for (final var uri : pathes.get(source)) {
if (progress.isCanceled()) {
return;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_7, uri));
}
resourceSet.getResource(uri, true);
}
}
}
/** Create a temporary subdirectory inside the root temp directory.
*
* @param namePrefix the prefix for the folder name.
* @return the temp directory.
* @see #getTempDirectory()
*/
protected File createTempDir(String namePrefix) {
final var tempDir = new File(getTempDirectory(), namePrefix);
cleanFolder(tempDir, null);
if (!tempDir.mkdirs()) {
throw new RuntimeException(MessageFormat.format(Messages.SarlBatchCompiler_8, tempDir.getAbsolutePath()));
}
this.tempFolders.add(tempDir);
return tempDir;
}
/** Clean the folders.
*
* @param parentFolder the parent folder.
* @param filter the file filter for the file to remove.
* @return the success status.
*/
protected boolean cleanFolder(File parentFolder, FileFilter filter) {
try {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_9, parentFolder.toString()));
}
return Files.cleanFolder(parentFolder, null, true, true);
} catch (FileNotFoundException e) {
return true;
}
}
/** Check the compiler configuration; and logs errors.
*
* @param progress monitor of the progress of the compilation.
* @return success status. Replies {@code false} if the operation is canceled.
*/
protected boolean checkConfiguration(IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_55);
final var output = getOutputPath();
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_35, output));
}
if (output == null) {
reportInternalError(Messages.SarlBatchCompiler_36);
return false;
}
progress.subTask(Messages.SarlBatchCompiler_56);
for (final var sourcePath : getSourcePaths()) {
if (progress.isCanceled()) {
return false;
}
try {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_37, sourcePath));
}
if (isContainedIn(output.getCanonicalFile(), sourcePath.getCanonicalFile())) {
reportInternalError(Messages.SarlBatchCompiler_10, output, sourcePath);
return false;
}
} catch (IOException e) {
reportInternalError(Messages.SarlBatchCompiler_11, e);
}
}
return true;
}
private static boolean isContainedIn(File child, File possibleParent) {
var parent = child;
while (parent != null) {
if (parent.equals(possibleParent)) {
return true;
}
parent = parent.getParentFile();
}
return false;
}
private static LinkedList splitFile(File file, IProgressMonitor progress) {
assert progress != null;
final var elements = new LinkedList();
File current = file;
do {
if (progress.isCanceled()) {
return null;
}
elements.addFirst(current.getName());
current = current.getParentFile();
} while (current != null);
return elements;
}
private File determineCommonRoot(Iterable files, IProgressMonitor progress) {
assert progress != null;
if (this.baseUri != null) {
if (this.baseUri.isFile()) {
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_32, this.baseUri));
}
return new File(this.baseUri.toFileString());
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_33, this.baseUri));
}
}
LinkedList longuestPrefix = null;
for (final var file : files) {
if (progress.isCanceled()) {
return null;
}
if (file != null) {
final var components = splitFile(file, progress);
if (longuestPrefix == null) {
longuestPrefix = components;
} else {
int i = 0;
while (i < longuestPrefix.size() && i < components.size()
&& Strings.equal(longuestPrefix.get(i), components.get(i))) {
if (progress.isCanceled()) {
return null;
}
++i;
}
while (i < longuestPrefix.size()) {
if (progress.isCanceled()) {
return null;
}
longuestPrefix.removeLast();
}
if (longuestPrefix.isEmpty()) {
return null;
}
}
}
}
if (longuestPrefix == null || progress.isCanceled()) {
return null;
}
File prefix = null;
for (final String component : longuestPrefix) {
if (progress.isCanceled()) {
return null;
}
if (prefix == null) {
prefix = new File(component);
} else {
prefix = new File(prefix, component);
}
}
return prefix;
}
private boolean configureWorkspace(ResourceSet resourceSet, IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_57);
final var sourceFolders = getSourcePaths();
final var javaOutputFile = getOutputPath();
final var classOutputFile = getClassOutputPath();
if (sourceFolders == null || sourceFolders.isEmpty() || javaOutputFile == null
|| classOutputFile == null || progress.isCanceled()) {
if (sourceFolders == null || sourceFolders.isEmpty()) {
reportInternalError(Messages.SarlBatchCompiler_60);
}
if (javaOutputFile == null) {
reportInternalError(Messages.SarlBatchCompiler_61);
}
if (classOutputFile == null) {
reportInternalError(Messages.SarlBatchCompiler_62);
}
return false;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_31, this.baseUri));
}
final var commonRoot = determineCommonRoot(
Iterables.concat(sourceFolders, Arrays.asList(javaOutputFile, classOutputFile)),
progress);
if (progress.isCanceled()) {
return false;
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_34, commonRoot));
}
if (commonRoot == null) {
reportInternalError(Messages.SarlBatchCompiler_12);
for (final var sourceFile : sourceFolders) {
reportInternalError(Messages.SarlBatchCompiler_13, sourceFile);
}
reportInternalError(Messages.SarlBatchCompiler_14, javaOutputFile);
return false;
}
this.projectConfig = new FileProjectConfig(commonRoot, commonRoot.getName());
if (progress.isCanceled()) {
return false;
}
final var commonURI = commonRoot.toURI();
final var relativizedTarget = commonURI.relativize(javaOutputFile.toURI());
if (progress.isCanceled()) {
return false;
}
if (relativizedTarget.isAbsolute()) {
reportInternalError(Messages.SarlBatchCompiler_15, javaOutputFile, commonRoot);
return false;
}
final var slash = CharMatcher.is('/');
final var relativeTargetFolder = slash.trimTrailingFrom(relativizedTarget.getPath());
final var allOutputConfigurations = this.outputConfigurationProvider.getOutputConfigurations();
if (progress.isCanceled()) {
return false;
}
this.outputConfigurations = new TreeMap<>();
for (final var configuration : allOutputConfigurations) {
if (progress.isCanceled()) {
return false;
}
this.outputConfigurations.put(configuration.getName(), configuration);
if (Strings.equal(configuration.getName(), IFileSystemAccess.DEFAULT_OUTPUT)) {
configuration.setOutputDirectory(new File(commonRoot, relativeTargetFolder).getAbsolutePath());
} else {
var outFile = new File(configuration.getOutputDirectory());
outFile = new File(commonRoot, outFile.getPath());
configuration.setOutputDirectory(outFile.getAbsolutePath());
}
}
if (progress.isCanceled()) {
return false;
}
for (final var source : sourceFolders) {
if (progress.isCanceled()) {
return false;
}
final var relSource = commonURI.relativize(source.toURI());
if (relSource.isAbsolute()) {
reportInternalError(Messages.SarlBatchCompiler_16, source, commonRoot);
return false;
}
this.projectConfig.addSourceFolder(slash.trimTrailingFrom(relSource.getPath()));
}
if (progress.isCanceled()) {
return false;
}
final var outputConfigurations = new HashMap>();
outputConfigurations.put(this.languageName, allOutputConfigurations);
ProjectConfigAdapter.install(resourceSet, this.projectConfig);
resourceSet.eAdapters().add(new OutputConfigurationAdapter(outputConfigurations));
if (progress.isCanceled()) {
return false;
}
return true;
}
/**
* Installs the JvmTypeProvider optionally including index access into the {@link ResourceSet}. The lookup classpath
* is enhanced with the given tmp directory.
*
* @param resourceSet the resource set that will be compiled.
* @param temporaryClassDirectory the directory where the class files of the stubs are generated.
* @param skipIndexLookup indicates if the index should be used for looking up types.
* @param cancelIndicator monitor for cancelling the compilation.
*/
@SuppressWarnings("unused")
private void installJvmTypeProvider(ResourceSet resourceSet, File temporaryClassDirectory, boolean skipIndexLookup,
IProgressMonitor progress) {
assert progress != null;
progress.subTask(Messages.SarlBatchCompiler_58);
final Iterable classpath;
final Iterable modulepath;
if (temporaryClassDirectory != null) {
if (isModularProject()) {
classpath = getClassPath();
modulepath = Iterables.concat(
Collections.singletonList(temporaryClassDirectory),
getModulePath(), getSourcePaths());
} else {
classpath = Iterables.concat(
Collections.singletonList(temporaryClassDirectory),
getClassPath(), getSourcePaths());
modulepath = getModulePath();
}
} else {
if (isModularProject()) {
classpath = getClassPath();
modulepath = Iterables.concat(
getModulePath(), getSourcePaths());
} else {
classpath = Iterables.concat(
getClassPath(), getSourcePaths());
modulepath = getModulePath();
}
}
if (getLogger().isLoggable(Level.FINEST)) {
getLogger().finest(MessageFormat.format(Messages.SarlBatchCompiler_17, classpath));
}
if (progress.isCanceled()) {
return;
}
final ClassLoader parentClassLoader;
if (isUseCurrentClassLoaderAsParent()) {
parentClassLoader = getClass().getClassLoader();
} else {
parentClassLoader = getCurrentClassLoader();
}
if (progress.isCanceled()) {
return;
}
this.jvmTypesClassLoader = createClassLoader(classpath, modulepath, parentClassLoader);
if (progress.isCanceled()) {
return;
}
new ClasspathTypeProvider(this.jvmTypesClassLoader, resourceSet, skipIndexLookup ? null : this.indexedJvmTypeAccess, null);
if (progress.isCanceled()) {
return;
}
((XtextResourceSet) resourceSet).setClasspathURIContext(this.jvmTypesClassLoader);
if (progress.isCanceled()) {
return;
}
// for annotation processing we need to have the compiler's classpath as a parent.
progress.subTask(Messages.SarlBatchCompiler_59);
this.annotationProcessingClassLoader = createClassLoader(classpath, modulepath, getCurrentClassLoader());
if (progress.isCanceled()) {
return;
}
resourceSet.eAdapters().add(new ProcessorInstanceForJvmTypeProvider.ProcessorClassloaderAdapter(this.annotationProcessingClassLoader));
}
private static Iterable toURL(Iterable files) {
return Iterables.transform(files, from -> {
try {
final URL url = from.toURI().toURL();
assert url != null;
return url;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
/** Create the project class loader.
*
* @param classPath the project class path.
* @param modulePath the project class path.
* @param parentClassLoader the parent class loader.
* @return the class loader for the project.
*/
@SuppressWarnings("static-method")
protected ClassLoader createClassLoader(Iterable classPath, Iterable modulePath, ClassLoader parentClassLoader) {
return new URLClassLoader(Iterables.toArray(
toURL(Iterables.concat(classPath, modulePath)),
URL.class), parentClassLoader);
}
/** Null-safe destruction of the given class loaders.
*
* @param classLoader the class loader to destroy.
*/
protected void destroyClassLoader(ClassLoader classLoader) {
if (classLoader instanceof Closeable ccl) {
try {
ccl.close();
} catch (Exception e) {
reportInternalWarning(Messages.SarlBatchCompiler_18, e);
}
}
}
/** Change the severity level of a warning.
*
* @param warningId the identifier of the warning. If {@code null} or empty, this function does nothing.
* @param severity the new severity. If {@code null} this function does nothing.
* @since 0.5
*/
public void setWarningSeverity(String warningId, Severity severity) {
if (!Strings.isEmpty(warningId) && severity != null) {
this.issueSeverityProvider.setSeverity(warningId, severity);
}
}
/** Change the severity level of for all the warnings.
*
* @param severity the new severity. If {@code null} this function does nothing.
* @since 0.5
*/
public void setAllWarningSeverities(Severity severity) {
if (severity != null) {
this.issueSeverityProvider.setAllSeverities(severity);
}
}
private static class LoggerRepositoryWrapper implements LoggerRepository {
private final LoggerRepository original;
private final Map wrapped = new HashMap<>();
/** Construct a wrapper to the given repository.
*
* @param original the repository to wrap out.
*/
LoggerRepositoryWrapper(LoggerRepository original) {
this.original = original;
}
/** Register a wrapping of a logger.
*
* @param loggerName the logger name.
* @param logger the logger.
*/
void registerWrapper(String loggerName, org.apache.log4j.Logger logger) {
this.wrapped.put(loggerName, logger);
}
@Override
public void addHierarchyEventListener(HierarchyEventListener listener) {
this.original.addHierarchyEventListener(listener);
}
@Override
public boolean isDisabled(int level) {
return this.original.isDisabled(level);
}
@Override
public void setThreshold(org.apache.log4j.Level level) {
this.original.setThreshold(level);
}
@Override
public void setThreshold(String val) {
this.original.setThreshold(val);
}
@Override
public void emitNoAppenderWarning(Category cat) {
this.original.emitNoAppenderWarning(cat);
}
@Override
public org.apache.log4j.Level getThreshold() {
return this.original.getThreshold();
}
@Override
public org.apache.log4j.Logger getLogger(String name) {
final var wrapped = this.wrapped.get(name);
if (wrapped != null) {
return wrapped;
}
return this.original.getLogger(name);
}
@Override
public org.apache.log4j.Logger getLogger(String name, LoggerFactory factory) {
final var wrapped = this.wrapped.get(name);
if (wrapped != null) {
return wrapped;
}
return this.original.getLogger(name, factory);
}
@Override
public org.apache.log4j.Logger getRootLogger() {
return this.original.getRootLogger();
}
@Override
public org.apache.log4j.Logger exists(String name) {
return null;
}
@Override
public void shutdown() {
this.original.shutdown();
}
@Override
public Enumeration> getCurrentLoggers() {
return this.getCurrentLoggers();
}
@Override
public Enumeration> getCurrentCategories() {
return this.original.getCurrentCategories();
}
@Override
public void fireAddAppenderEvent(Category logger, Appender appender) {
this.original.fireAddAppenderEvent(logger, appender);
}
@Override
public void resetConfiguration() {
this.original.resetConfiguration();
}
}
}