View Javadoc
1   /*
2    * Copyright 2018 SPF4J.
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  package org.spf4j.maven.plugin.avro.avscp;
17  
18  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19  import java.io.BufferedInputStream;
20  import java.io.BufferedReader;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.UncheckedIOException;
24  import java.nio.charset.StandardCharsets;
25  import java.nio.file.Files;
26  import java.nio.file.NoSuchFileException;
27  import java.nio.file.Path;
28  import java.util.Collections;
29  import java.util.Map;
30  import java.util.Properties;
31  import org.apache.avro.Schema;
32  import org.apache.avro.SchemaRefWriter;
33  import org.apache.avro.SchemaResolver;
34  import org.apache.avro.SchemaResolvers;
35  import org.apache.maven.execution.MavenSession;
36  import org.apache.maven.plugin.AbstractMojo;
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.plugin.MojoFailureException;
39  import org.apache.maven.plugins.annotations.Component;
40  import org.apache.maven.plugins.annotations.Parameter;
41  import org.apache.maven.project.MavenProject;
42  import org.eclipse.aether.RepositorySystem;
43  import org.spf4j.avro.SchemaRef;
44  import org.spf4j.maven.MavenSchemaResolver;
45  import static org.spf4j.maven.plugin.avro.avscp.SchemaCompileMojo.SCHEMA_INDEX_FILENAME;
46  
47  /**
48   * @author Zoltan Farkas
49   */
50  @SuppressWarnings("checkstyle:VisibilityModifier")
51  @SuppressFBWarnings("AI_ANNOTATION_ISSUES_NEEDS_NULLABLE")
52  abstract class SchemaMojoBase extends AbstractMojo {
53  
54  
55    @Parameter(defaultValue = "${project}", required = true, readonly = true)
56    protected MavenProject mavenProject;
57  
58  
59    /**
60     * The directory where all schema dependencies (avsc, avpr, avdl) are made vailable
61     */
62    @Parameter(name = "dependenciesDirectory",
63            defaultValue = "${project.build.directory}/schema-dependencies", readonly = true)
64    protected File dependenciesDirectory;
65  
66    /**
67     * The source directory of avro files. This directory is added to the classpath at schema compiling time. All files
68     * can therefore be referenced as classpath resources following the directory structure under the source directory.
69     */
70    @Parameter(name = "sourceDirectory", defaultValue = "${basedir}/src/main/avro")
71    protected File sourceDirectory;
72  
73  
74    /**
75     *  the destination for the java generated files.
76     */
77    @Parameter(name = "generatedJavaTarget",
78            defaultValue = "${project.build.directory}/generated-sources/avro")
79    protected File generatedJavaTarget;
80  
81  
82    /**
83     * the destination for the generated avro schema json files (will be published along with the java code).
84     */
85    @Parameter(name = "generatedAvscTarget",
86            defaultValue = "${project.build.directory}/generated-sources/avsc")
87    protected File generatedAvscTarget;
88  
89  
90    /**
91     *  the target folder.
92     */
93    @Parameter(name = "target", defaultValue = "${project.build.directory}")
94    protected File target;
95  
96    /**
97     * The current build mavenSession instance.
98     */
99    @Parameter(defaultValue = "${session}", required = true, readonly = true)
100   protected MavenSession mavenSession;
101 
102   /**
103    * This option will use schema references when writing schemas that depend of schemas from other projects,
104    * instead of baking them in.
105    * by default (false) all schema references will be inlined.
106    */
107   @Parameter(name = "useSchemaReferencesForAvsc",
108           defaultValue = "false")
109   protected boolean useSchemaReferencesForAvsc = false;
110 
111   /**
112    *  the schema artifact classifier.
113    */
114   @Parameter(name = "schemaArtifactClassifier", defaultValue = "avsc")
115   protected String schemaArtifactClassifier = "avsc";
116 
117   /**
118    *  the schema artifact extension.
119    */
120   @Parameter(name = "schemaArtifactExtension", defaultValue = "jar")
121   protected String schemaArtifactExtension = "jar";
122 
123 
124   /**
125    * The entry point to Aether, i.e. the component doing all the work.
126    */
127   @Component
128   protected  RepositorySystem repoSystem;
129 
130   public final RepositorySystem getRepoSystem() {
131     return repoSystem;
132   }
133 
134   public final MavenSession getMavenSession() {
135     return mavenSession;
136   }
137 
138   public final MavenProject getMavenProject() {
139     return mavenProject;
140   }
141 
142   public final File getGeneratedAvscTarget() {
143     return generatedAvscTarget;
144   }
145 
146   public final File getTarget() {
147     return target;
148   }
149 
150  private Map<String, String> idx2Name() throws IOException {
151     Path indexFile = generatedAvscTarget.toPath().resolve(SCHEMA_INDEX_FILENAME);
152     Properties result = new Properties();
153     try (BufferedReader br = Files.newBufferedReader(indexFile, StandardCharsets.UTF_8)) {
154       result.load(br);
155     } catch (NoSuchFileException ex) {
156       return Collections.EMPTY_MAP;
157     }
158     return (Map) result;
159   }
160 
161   /**
162    * Children must call this.
163    * @throws MojoExecutionException
164    * @throws MojoFailureException
165    */
166   @Override
167   public void execute() throws MojoExecutionException, MojoFailureException {
168     if (useSchemaReferencesForAvsc && SchemaRefWriter.isSchemaRefsSupported()) {
169       Map<String, String> currentMappings;
170       try {
171         currentMappings = idx2Name();
172       } catch (IOException ex) {
173         throw new MojoExecutionException("Exception loading schema index: "
174                 + generatedAvscTarget.toPath().resolve(SCHEMA_INDEX_FILENAME), ex);
175       }
176       MavenSchemaResolver res = new MavenSchemaResolver(repoSystem, getMavenSession().getRepositorySession(),
177               mavenProject.getRemoteProjectRepositories(), schemaArtifactClassifier, schemaArtifactExtension);
178       SchemaResolvers.registerDefault(new SchemaResolver() {
179         @Override
180         public Schema resolveSchema(final String id) {
181           SchemaRef ref = new SchemaRef(id);
182           if (mavenProject.getGroupId().equals(ref.getGroupId())
183                   && mavenProject.getArtifactId().equals(ref.getArtifactId())
184                   && mavenProject.getVersion().equals(ref.getVersion())) {
185             String name = currentMappings.get(ref.getRef());
186             Path schemaPath = generatedAvscTarget.toPath().resolve(name.replace('.', '/') + ".avsc");
187             try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(schemaPath))) {
188               return new Schema.Parser().parse(bis);
189             } catch (IOException ex) {
190               throw new UncheckedIOException(ex);
191             }
192           } else {
193             return res.resolveSchema(id);
194           }
195         }
196 
197         @Override
198         public String getId(final Schema schema) {
199           return res.getId(schema);
200         }
201       });
202     }
203   }
204 
205 
206 
207 
208   /**
209    * will be overwritten as needed, and override will include this result.
210    */
211   @Override
212   public String toString() {
213     return "SchemaMojoBase{" + "dependenciesDirectory=" + dependenciesDirectory
214             + ", sourceDirectory=" + sourceDirectory + ", generatedJavaTarget="
215             + generatedJavaTarget + ", generatedAvscTarget=" + generatedAvscTarget + ", target=" + target + '}';
216   }
217 
218 
219 
220 }