1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.spf4j.maven;
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.net.URI;
24 import java.nio.file.FileSystem;
25 import java.nio.file.FileSystemAlreadyExistsException;
26 import java.nio.file.FileSystems;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Properties;
32 import java.util.zip.ZipError;
33 import org.apache.avro.AvroRuntimeException;
34 import org.apache.avro.Schema;
35 import org.apache.avro.SchemaResolver;
36 import org.apache.avro.SchemaResolvers;
37 import org.eclipse.aether.RepositorySystem;
38 import org.eclipse.aether.RepositorySystemSession;
39 import org.eclipse.aether.repository.RemoteRepository;
40 import org.eclipse.aether.resolution.ArtifactResolutionException;
41 import org.spf4j.avro.SchemaRef;
42 import static org.spf4j.maven.MavenRepositoryUtils.getRepositorySystem;
43 import static org.spf4j.maven.MavenRepositoryUtils.getRepositorySystemSession;
44
45
46
47
48 public final class MavenSchemaResolver implements SchemaResolver {
49
50 private final RepositorySystem repoSystem;
51
52 private final RepositorySystemSession repoSystemSession;
53
54 private final List<RemoteRepository> remotes;
55
56 private final String classifier;
57
58 private final String extension;
59
60 @SuppressFBWarnings("EI_EXPOSE_REP2")
61 public MavenSchemaResolver(final RepositorySystem repoSystem, final RepositorySystemSession repoSystemSession,
62 final List<RemoteRepository> remotes, final String classifier, final String extension) {
63 this.repoSystem = repoSystem;
64 this.repoSystemSession = repoSystemSession;
65 this.remotes = remotes;
66 this.classifier = classifier;
67 this.extension = extension;
68 }
69
70 @SuppressFBWarnings("EI_EXPOSE_REP2")
71 public MavenSchemaResolver(final List<RemoteRepository> repos,
72 final File localRepo, final String classifier, final String extension) {
73 RepositorySystem repositorySystem = getRepositorySystem();
74 RepositorySystemSession repositorySystemSession = getRepositorySystemSession(repositorySystem, localRepo);
75 this.repoSystem = repositorySystem;
76 this.repoSystemSession = repositorySystemSession;
77 this.remotes = repos;
78 this.classifier = classifier;
79 this.extension = extension;
80 }
81
82 @Override
83 @SuppressFBWarnings("PCAIL_POSSIBLE_CONSTANT_ALLOCATION_IN_LOOP")
84 public Schema resolveSchema(final String id) {
85 SchemaRef ref = new SchemaRef(id);
86 try {
87 File artifact = MavenRepositoryUtils.resolveArtifact(ref.getGroupId(), ref.getArtifactId(),
88 classifier, extension, ref.getVersion(), remotes, repoSystem, repoSystemSession);
89 URI zipUri = URI.create("jar:" + artifact.toURI().toURL());
90 FileSystem zipFs;
91 synchronized (zipUri.toString().intern()) {
92 try {
93 zipFs = FileSystems.newFileSystem(zipUri, Collections.emptyMap());
94 } catch (FileSystemAlreadyExistsException ex) {
95 zipFs = FileSystems.getFileSystem(zipUri);
96 } catch (ZipError ze) {
97 throw new AvroRuntimeException("Cannot resolve " + id, ze);
98 }
99 }
100 for (Path root : zipFs.getRootDirectories()) {
101 Path index = root.resolve("schema_index.properties");
102 if (Files.exists(index)) {
103 Properties prop = new Properties();
104 try (BufferedReader indexReader = Files.newBufferedReader(index)) {
105 prop.load(indexReader);
106 }
107 String schemaName = prop.getProperty(ref.getRef());
108 if (schemaName == null) {
109 throw new AvroRuntimeException("unable to resolve schema: " + id + " missing from index " + index);
110 }
111 Path schemaPath = root.resolve(schemaName.replace('.', '/') + ".avsc");
112 try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(schemaPath))) {
113 return new Schema.Parser().parse(bis);
114 }
115 }
116 }
117 throw new IOException("unable to resolve schema: " + id);
118
119 } catch (ArtifactResolutionException | IOException ex) {
120 throw new AvroRuntimeException("Cannot resolve " + id, ex);
121 }
122 }
123
124 @Override
125 public String getId(final Schema schema) {
126 return schema.getProp("mvnId");
127 }
128
129 @Override
130 public void registerAsDefault() {
131 SchemaResolvers.registerDefault(this);
132 }
133
134 @Override
135 public String toString() {
136 return "MavenSchemaResolver{" + "repoSystem=" + repoSystem + ", repoSystemSession=" + repoSystemSession
137 + ", remotes=" + remotes + ", classifier=" + classifier + ", extension=" + extension + '}';
138 }
139
140
141
142 }