1 package org.apache.archiva.consumers.core;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.admin.model.beans.ManagedRepository;
23 import org.apache.archiva.configuration.ArchivaConfiguration;
24 import org.apache.archiva.configuration.ConfigurationNames;
25 import org.apache.archiva.configuration.FileTypes;
26 import org.apache.archiva.consumers.AbstractMonitoredConsumer;
27 import org.apache.archiva.consumers.ConsumerException;
28 import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
29 import org.apache.archiva.model.ArtifactReference;
30 import org.apache.archiva.model.ProjectReference;
31 import org.apache.archiva.model.VersionedReference;
32 import org.apache.archiva.repository.ContentNotFoundException;
33 import org.apache.archiva.repository.ManagedRepositoryContent;
34 import org.apache.archiva.repository.RepositoryContentFactory;
35 import org.apache.archiva.repository.RepositoryException;
36 import org.apache.archiva.repository.RepositoryNotFoundException;
37 import org.apache.archiva.repository.layout.LayoutException;
38 import org.apache.archiva.repository.metadata.MetadataTools;
39 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
40 import org.apache.archiva.redback.components.registry.Registry;
41 import org.apache.archiva.redback.components.registry.RegistryListener;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.springframework.context.annotation.Scope;
45 import org.springframework.stereotype.Service;
46
47 import javax.annotation.PostConstruct;
48 import javax.inject.Inject;
49 import java.io.File;
50 import java.io.IOException;
51 import java.util.ArrayList;
52 import java.util.Date;
53 import java.util.List;
54
55
56
57
58
59
60 @Service( "knownRepositoryContentConsumer#metadata-updater" )
61 @Scope( "prototype" )
62 public class MetadataUpdaterConsumer
63 extends AbstractMonitoredConsumer
64 implements KnownRepositoryContentConsumer, RegistryListener
65 {
66 private Logger log = LoggerFactory.getLogger( MetadataUpdaterConsumer.class );
67
68
69
70
71 private String id = "metadata-updater";
72
73
74
75
76 private String description = "Update / Create maven-metadata.xml files";
77
78
79
80
81 @Inject
82 private RepositoryContentFactory repositoryFactory;
83
84
85
86
87 @Inject
88 private MetadataTools metadataTools;
89
90
91
92
93 @Inject
94 private ArchivaConfiguration configuration;
95
96
97
98
99 @Inject
100 private FileTypes filetypes;
101
102 private static final String TYPE_METADATA_BAD_INTERNAL_REF = "metadata-bad-internal-ref";
103
104 private static final String TYPE_METADATA_WRITE_FAILURE = "metadata-write-failure";
105
106 private static final String TYPE_METADATA_IO = "metadata-io-warning";
107
108 private ManagedRepositoryContent repository;
109
110 private File repositoryDir;
111
112 private List<String> includes = new ArrayList<String>( 0 );
113
114 private long scanStartTimestamp = 0;
115
116 public String getDescription()
117 {
118 return description;
119 }
120
121 public String getId()
122 {
123 return id;
124 }
125
126 public void setIncludes( List<String> includes )
127 {
128 this.includes = includes;
129 }
130
131 public void beginScan( ManagedRepository repoConfig, Date whenGathered )
132 throws ConsumerException
133 {
134 try
135 {
136 this.repository = repositoryFactory.getManagedRepositoryContent( repoConfig.getId() );
137 this.repositoryDir = new File( repository.getRepoRoot() );
138 this.scanStartTimestamp = System.currentTimeMillis();
139 }
140 catch ( RepositoryNotFoundException e )
141 {
142 throw new ConsumerException( e.getMessage(), e );
143 }
144 catch ( RepositoryException e )
145 {
146 throw new ConsumerException( e.getMessage(), e );
147 }
148 }
149
150 public void beginScan( ManagedRepository repository, Date whenGathered, boolean executeOnEntireRepo )
151 throws ConsumerException
152 {
153 beginScan( repository, whenGathered );
154 }
155
156 public void completeScan()
157 {
158
159 }
160
161 public void completeScan( boolean executeOnEntireRepo )
162 {
163 completeScan();
164 }
165
166 public List<String> getExcludes()
167 {
168 return getDefaultArtifactExclusions();
169 }
170
171 public List<String> getIncludes()
172 {
173 return this.includes;
174 }
175
176 public void processFile( String path )
177 throws ConsumerException
178 {
179
180 if ( !path.startsWith( "." ) )
181 {
182 try
183 {
184 ArtifactReference artifact = repository.toArtifactReference( path );
185 updateVersionMetadata( artifact, path );
186 updateProjectMetadata( artifact, path );
187 }
188 catch ( LayoutException e )
189 {
190 log.info( "Not processing path that is not an artifact: {} ({})", path, e.getMessage() );
191 }
192 }
193 }
194
195 public void processFile( String path, boolean executeOnEntireRepo )
196 throws Exception
197 {
198 processFile( path );
199 }
200
201 private void updateProjectMetadata( ArtifactReference artifact, String path )
202 {
203 ProjectReference projectRef = new ProjectReference();
204 projectRef.setGroupId( artifact.getGroupId() );
205 projectRef.setArtifactId( artifact.getArtifactId() );
206
207 try
208 {
209 String metadataPath = this.metadataTools.toPath( projectRef );
210
211 File projectMetadata = new File( this.repositoryDir, metadataPath );
212
213 if ( projectMetadata.exists() && ( projectMetadata.lastModified() >= this.scanStartTimestamp ) )
214 {
215
216 log.debug( "Skipping uptodate metadata: {}", this.metadataTools.toPath( projectRef ) );
217 return;
218 }
219
220 metadataTools.updateMetadata( this.repository, projectRef );
221 log.debug( "Updated metadata: {}", this.metadataTools.toPath( projectRef ) );
222 }
223 catch ( LayoutException e )
224 {
225 triggerConsumerWarning( TYPE_METADATA_BAD_INTERNAL_REF,
226 "Unable to convert path [" + path + "] to an internal project reference: "
227 + e.getMessage() );
228 }
229 catch ( RepositoryMetadataException e )
230 {
231 triggerConsumerError( TYPE_METADATA_WRITE_FAILURE,
232 "Unable to write project metadata for artifact [" + path + "]: " + e.getMessage() );
233 }
234 catch ( IOException e )
235 {
236 triggerConsumerWarning( TYPE_METADATA_IO,
237 "Project metadata not written due to IO warning: " + e.getMessage() );
238 }
239 catch ( ContentNotFoundException e )
240 {
241 triggerConsumerWarning( TYPE_METADATA_IO,
242 "Project metadata not written because no versions were found to update: "
243 + e.getMessage() );
244 }
245 }
246
247 private void updateVersionMetadata( ArtifactReference artifact, String path )
248 {
249 VersionedReference versionRef = new VersionedReference();
250 versionRef.setGroupId( artifact.getGroupId() );
251 versionRef.setArtifactId( artifact.getArtifactId() );
252 versionRef.setVersion( artifact.getVersion() );
253
254 try
255 {
256 String metadataPath = this.metadataTools.toPath( versionRef );
257
258 File projectMetadata = new File( this.repositoryDir, metadataPath );
259
260 if ( projectMetadata.exists() && ( projectMetadata.lastModified() >= this.scanStartTimestamp ) )
261 {
262
263 log.debug( "Skipping uptodate metadata: {}", this.metadataTools.toPath( versionRef ) );
264 return;
265 }
266
267 metadataTools.updateMetadata( this.repository, versionRef );
268 log.debug( "Updated metadata: {}", this.metadataTools.toPath( versionRef ) );
269 }
270 catch ( LayoutException e )
271 {
272 triggerConsumerWarning( TYPE_METADATA_BAD_INTERNAL_REF,
273 "Unable to convert path [" + path + "] to an internal version reference: "
274 + e.getMessage() );
275 }
276 catch ( RepositoryMetadataException e )
277 {
278 triggerConsumerError( TYPE_METADATA_WRITE_FAILURE,
279 "Unable to write version metadata for artifact [" + path + "]: " + e.getMessage() );
280 }
281 catch ( IOException e )
282 {
283 triggerConsumerWarning( TYPE_METADATA_IO,
284 "Version metadata not written due to IO warning: " + e.getMessage() );
285 }
286 catch ( ContentNotFoundException e )
287 {
288 triggerConsumerWarning( TYPE_METADATA_IO,
289 "Version metadata not written because no versions were found to update: "
290 + e.getMessage() );
291 }
292 }
293
294 public boolean isPermanent()
295 {
296 return false;
297 }
298
299 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
300 {
301 if ( ConfigurationNames.isRepositoryScanning( propertyName ) )
302 {
303 initIncludes();
304 }
305 }
306
307 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
308 {
309
310 }
311
312 private void initIncludes()
313 {
314 includes = new ArrayList<String>( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) );
315 }
316
317 @PostConstruct
318 public void initialize()
319 {
320 configuration.addChangeListener( this );
321
322 initIncludes();
323 }
324 }