1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.transformation.impl;
20
21 import javax.xml.stream.XMLStreamException;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.util.Objects;
31 import java.util.concurrent.atomic.AtomicReference;
32 import java.util.function.Supplier;
33
34 import org.apache.maven.artifact.DefaultArtifact;
35 import org.apache.maven.internal.transformation.TransformationFailedException;
36 import org.apache.maven.model.building.ModelBuildingException;
37 import org.apache.maven.project.MavenProject;
38 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
39 import org.eclipse.aether.RepositorySystemSession;
40
41
42
43
44
45
46 class TransformedArtifact extends DefaultArtifact {
47
48 private static final int SHA1_BUFFER_SIZE = 8192;
49 private final DefaultConsumerPomArtifactTransformer defaultConsumerPomArtifactTransformer;
50 private final MavenProject project;
51 private final Supplier<Path> sourcePathProvider;
52 private final Path target;
53 private final RepositorySystemSession session;
54 private final AtomicReference<String> sourceState;
55
56 TransformedArtifact(
57 DefaultConsumerPomArtifactTransformer defaultConsumerPomArtifactTransformer,
58 MavenProject project,
59 Path target,
60 RepositorySystemSession session,
61 org.apache.maven.artifact.Artifact source,
62 Supplier<Path> sourcePathProvider,
63 String classifier,
64 String extension) {
65 super(
66 source.getGroupId(),
67 source.getArtifactId(),
68 source.getVersionRange(),
69 source.getScope(),
70 extension,
71 classifier,
72 new TransformedArtifactHandler(
73 classifier, extension, source.getArtifactHandler().getPackaging()));
74 this.defaultConsumerPomArtifactTransformer = defaultConsumerPomArtifactTransformer;
75 this.project = project;
76 this.target = target;
77 this.session = session;
78 this.sourcePathProvider = sourcePathProvider;
79 this.sourceState = new AtomicReference<>(null);
80 }
81
82 @Override
83 public boolean isResolved() {
84 return getFile() != null;
85 }
86
87 @Override
88 public void setFile(File file) {
89 throw new UnsupportedOperationException("transformed artifact file cannot be set");
90 }
91
92 @Override
93 public synchronized File getFile() {
94 try {
95 String state = mayUpdate();
96 if (state == null) {
97 return null;
98 }
99 return target.toFile();
100 } catch (IOException
101 | NoSuchAlgorithmException
102 | XMLStreamException
103 | ModelBuildingException
104 | ComponentLookupException e) {
105 throw new TransformationFailedException(e);
106 }
107 }
108
109 private String mayUpdate()
110 throws IOException, NoSuchAlgorithmException, XMLStreamException, ModelBuildingException,
111 ComponentLookupException {
112 String result;
113 Path src = sourcePathProvider.get();
114 if (src == null) {
115 Files.deleteIfExists(target);
116 result = null;
117 } else if (!Files.exists(src)) {
118 Files.deleteIfExists(target);
119 result = "";
120 } else {
121 String current = sha1(src);
122 String existing = sourceState.get();
123 if (!Objects.equals(current, existing)) {
124 defaultConsumerPomArtifactTransformer.transform(project, session, src, target);
125 Files.setLastModifiedTime(target, Files.getLastModifiedTime(src));
126 }
127 result = current;
128 }
129 sourceState.set(result);
130 return result;
131 }
132
133 static String sha1(Path path) throws NoSuchAlgorithmException, IOException {
134 MessageDigest md = MessageDigest.getInstance("SHA-1");
135 try (InputStream fis = Files.newInputStream(path)) {
136 byte[] buffer = new byte[SHA1_BUFFER_SIZE];
137 int read;
138 while ((read = fis.read(buffer)) != -1) {
139 md.update(buffer, 0, read);
140 }
141 }
142 StringBuilder result = new StringBuilder();
143 for (byte b : md.digest()) {
144 result.append(String.format("%02x", b));
145 }
146 return result.toString();
147 }
148 }