001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package gov.nist.secauto.metaschema.maven.plugin; 007 008import gov.nist.secauto.metaschema.core.model.IModule; 009import gov.nist.secauto.metaschema.core.model.MetaschemaException; 010import gov.nist.secauto.metaschema.core.util.ObjectUtils; 011import gov.nist.secauto.metaschema.databind.IBindingContext; 012import gov.nist.secauto.metaschema.databind.codegen.JavaGenerator; 013import gov.nist.secauto.metaschema.databind.codegen.config.DefaultBindingConfiguration; 014 015import org.apache.maven.plugin.MojoExecutionException; 016import org.apache.maven.plugins.annotations.LifecyclePhase; 017import org.apache.maven.plugins.annotations.Mojo; 018import org.apache.maven.plugins.annotations.Parameter; 019 020import java.io.File; 021import java.io.IOException; 022import java.util.Arrays; 023import java.util.Collections; 024import java.util.List; 025import java.util.Set; 026 027import edu.umd.cs.findbugs.annotations.NonNull; 028 029/** 030 * Goal which generates Java source files for a given set of Metaschema modules. 031 */ 032@Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES) 033public class GenerateSourcesMojo 034 extends AbstractMetaschemaMojo { 035 private static final String STALE_FILE_NAME = "generateSourcesStaleFile"; 036 037 /** 038 * A set of binding configurations. 039 */ 040 @Parameter 041 protected File[] configs; 042 043 /** 044 * <p> 045 * Gets the last part of the stale filename. 046 * </p> 047 * <p> 048 * The full stale filename will be generated by pre-pending 049 * {@code "." + getExecution().getExecutionId()} to this staleFileName. 050 * 051 * @return the stale filename postfix 052 */ 053 @Override 054 protected String getStaleFileName() { 055 return STALE_FILE_NAME; 056 } 057 058 /** 059 * Retrieve a list of binding configurations. 060 * 061 * @return the collection of binding configurations 062 */ 063 protected List<File> getConfigs() { 064 List<File> retval; 065 if (configs == null) { 066 retval = Collections.emptyList(); 067 } else { 068 retval = Arrays.asList(configs); 069 } 070 return retval; 071 } 072 073 /** 074 * Generate the Java source files for the provided Metaschemas. 075 * 076 * @param modules 077 * the collection of Metaschema modules to generate sources for 078 * @throws MojoExecutionException 079 * if an error occurred while generating sources 080 */ 081 protected void generate(@NonNull Set<IModule> modules) throws MojoExecutionException { 082 DefaultBindingConfiguration bindingConfiguration = new DefaultBindingConfiguration(); 083 for (File config : getConfigs()) { 084 try { 085 if (getLog().isInfoEnabled()) { 086 getLog().info("Loading binding configuration: " + config.getPath()); 087 } 088 bindingConfiguration.load(config); 089 } catch (IOException ex) { 090 throw new MojoExecutionException( 091 String.format("Unable to load binding configuration from '%s'.", config.getPath()), ex); 092 } 093 } 094 095 try { 096 if (getLog().isInfoEnabled()) { 097 getLog().info("Generating Java classes in: " + getOutputDirectory().getPath()); 098 } 099 JavaGenerator.generate(modules, ObjectUtils.notNull(getOutputDirectory().toPath()), 100 bindingConfiguration); 101 } catch (IOException ex) { 102 throw new MojoExecutionException("Creation of Java classes failed.", ex); 103 } 104 } 105 106 @SuppressWarnings("PMD.AvoidCatchingGenericException") 107 @Override 108 public void execute() throws MojoExecutionException { 109 File staleFile = getStaleFile(); 110 try { 111 staleFile = ObjectUtils.notNull(staleFile.getCanonicalFile()); 112 } catch (IOException ex) { 113 if (getLog().isWarnEnabled()) { 114 getLog().warn("Unable to resolve canonical path to stale file. Treating it as not existing.", ex); 115 } 116 } 117 118 boolean generate; 119 if (shouldExecutionBeSkipped()) { 120 if (getLog().isDebugEnabled()) { 121 getLog().debug(String.format("Source file generation is configured to be skipped. Skipping.")); 122 } 123 generate = false; 124 } else if (staleFile.exists()) { 125 generate = isGenerationRequired(); 126 } else { 127 if (getLog().isInfoEnabled()) { 128 getLog().info(String.format("Stale file '%s' doesn't exist! Generating source files.", staleFile.getPath())); 129 } 130 generate = true; 131 } 132 133 if (generate) { 134 performGeneration(); 135 createStaleFile(staleFile); 136 137 // for m2e 138 getBuildContext().refresh(getOutputDirectory()); 139 } 140 141 // add generated sources to Maven 142 try { 143 getMavenProject().addCompileSourceRoot(getOutputDirectory().getCanonicalFile().getPath()); 144 } catch (IOException ex) { 145 throw new MojoExecutionException("Unable to add output directory to maven sources.", ex); 146 } 147 } 148 149 @SuppressWarnings("PMD.AvoidCatchingGenericException") 150 private void performGeneration() throws MojoExecutionException { 151 File outputDir = getOutputDirectory(); 152 if (getLog().isDebugEnabled()) { 153 getLog().debug(String.format("Using outputDirectory: %s", outputDir.getPath())); 154 } 155 156 if (!outputDir.exists() && !outputDir.mkdirs()) { 157 throw new MojoExecutionException("Unable to create output directory: " + outputDir); 158 } 159 160 IBindingContext bindingContext; 161 try { 162 bindingContext = newBindingContext(); 163 } catch (MetaschemaException | IOException ex) { 164 throw new MojoExecutionException("Failed to create the binding context", ex); 165 } 166 167 // generate Java sources based on provided metaschema sources 168 Set<IModule> modules; 169 try { 170 modules = getModulesToGenerateFor(bindingContext); 171 } catch (Exception ex) { 172 throw new MojoExecutionException("Loading of metaschema modules failed", ex); 173 } 174 175 generate(modules); 176 } 177}