001package org.apache.archiva.consumers.core; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.configuration.ArchivaConfiguration; 023import org.apache.archiva.configuration.FileTypes; 024import org.apache.archiva.consumers.AbstractMonitoredConsumer; 025import org.apache.archiva.consumers.ConsumerException; 026import org.apache.archiva.consumers.KnownRepositoryContentConsumer; 027import org.apache.archiva.model.ArtifactReference; 028import org.apache.archiva.model.ProjectReference; 029import org.apache.archiva.model.VersionedReference; 030import org.apache.archiva.repository.LayoutException; 031import org.apache.archiva.repository.ManagedRepository; 032import org.apache.archiva.repository.ManagedRepositoryContent; 033import org.apache.archiva.repository.RepositoryException; 034import org.apache.archiva.repository.RepositoryNotFoundException; 035import org.apache.archiva.repository.RepositoryRegistry; 036import org.apache.archiva.repository.metadata.base.MetadataTools; 037import org.apache.archiva.repository.metadata.RepositoryMetadataException; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040import org.springframework.context.annotation.Scope; 041import org.springframework.stereotype.Service; 042 043import javax.annotation.PostConstruct; 044import javax.inject.Inject; 045import java.io.IOException; 046import java.nio.file.Files; 047import java.nio.file.Path; 048import java.nio.file.Paths; 049import java.util.ArrayList; 050import java.util.Date; 051import java.util.List; 052 053/** 054 * MetadataUpdaterConsumer will create and update the metadata present within the repository. 055 */ 056@Service( "knownRepositoryContentConsumer#metadata-updater" ) 057@Scope( "prototype" ) 058public class MetadataUpdaterConsumer 059 extends AbstractMonitoredConsumer 060 implements KnownRepositoryContentConsumer 061 // it's prototype bean so we assume configuration won't change during a run 062 //, RegistryListener 063{ 064 private Logger log = LoggerFactory.getLogger( MetadataUpdaterConsumer.class ); 065 066 /** 067 * default-value="metadata-updater" 068 */ 069 private String id = "metadata-updater"; 070 071 private String description = "Update / Create maven-metadata.xml files"; 072 073 @Inject 074 private RepositoryRegistry repositoryRegistry; 075 076 @Inject 077 private MetadataTools metadataTools; 078 079 @Inject 080 private ArchivaConfiguration configuration; 081 082 @Inject 083 private FileTypes filetypes; 084 085 private static final String TYPE_METADATA_BAD_INTERNAL_REF = "metadata-bad-internal-ref"; 086 087 private static final String TYPE_METADATA_WRITE_FAILURE = "metadata-write-failure"; 088 089 private static final String TYPE_METADATA_IO = "metadata-io-warning"; 090 091 private ManagedRepositoryContent repository; 092 093 private Path repositoryDir; 094 095 private List<String> includes = new ArrayList<>( 0 ); 096 097 private long scanStartTimestamp = 0; 098 099 @Override 100 public String getDescription( ) 101 { 102 return description; 103 } 104 105 @Override 106 public String getId( ) 107 { 108 return id; 109 } 110 111 public void setIncludes( List<String> includes ) 112 { 113 this.includes = includes; 114 } 115 116 @Override 117 public void beginScan( ManagedRepository repoConfig, Date whenGathered ) 118 throws ConsumerException 119 { 120 try 121 { 122 ManagedRepository repo = repositoryRegistry.getManagedRepository( repoConfig.getId( ) ); 123 if (repo==null) { 124 throw new RepositoryNotFoundException( "Repository not found: "+repoConfig.getId() ); 125 } 126 this.repository = repo.getContent(); 127 if (this.repository==null) { 128 throw new RepositoryNotFoundException( "Repository content not found: "+repoConfig.getId() ); 129 } 130 this.repositoryDir = Paths.get( repository.getRepoRoot( ) ); 131 this.scanStartTimestamp = System.currentTimeMillis( ); 132 } 133 catch ( RepositoryException e ) 134 { 135 throw new ConsumerException( e.getMessage( ), e ); 136 } 137 } 138 139 @Override 140 public void beginScan( ManagedRepository repository, Date whenGathered, boolean executeOnEntireRepo ) 141 throws ConsumerException 142 { 143 beginScan( repository, whenGathered ); 144 } 145 146 @Override 147 public void completeScan( ) 148 { 149 /* do nothing here */ 150 } 151 152 @Override 153 public void completeScan( boolean executeOnEntireRepo ) 154 { 155 completeScan( ); 156 } 157 158 @Override 159 public List<String> getExcludes( ) 160 { 161 return getDefaultArtifactExclusions( ); 162 } 163 164 @Override 165 public List<String> getIncludes( ) 166 { 167 return this.includes; 168 } 169 170 @Override 171 public void processFile( String path ) 172 throws ConsumerException 173 { 174 // Ignore paths like .index etc 175 if ( !path.startsWith( "." ) ) 176 { 177 try 178 { 179 ArtifactReference artifact = repository.toArtifactReference( path ); 180 updateVersionMetadata( artifact, path ); 181 updateProjectMetadata( artifact, path ); 182 } 183 catch ( LayoutException e ) 184 { 185 log.info( "Not processing path that is not an artifact: {} ({})", path, e.getMessage( ) ); 186 } 187 } 188 } 189 190 @Override 191 public void processFile( String path, boolean executeOnEntireRepo ) 192 throws Exception 193 { 194 processFile( path ); 195 } 196 197 private void updateProjectMetadata( ArtifactReference artifact, String path ) 198 { 199 ProjectReference projectRef = new ProjectReference( ); 200 projectRef.setGroupId( artifact.getGroupId( ) ); 201 projectRef.setArtifactId( artifact.getArtifactId( ) ); 202 203 try 204 { 205 String metadataPath = this.metadataTools.toPath( projectRef ); 206 207 Path projectMetadata = this.repositoryDir.resolve( metadataPath ); 208 209 if ( Files.exists(projectMetadata) && ( Files.getLastModifiedTime( projectMetadata).toMillis() >= this.scanStartTimestamp ) ) 210 { 211 // This metadata is up to date. skip it. 212 log.debug( "Skipping uptodate metadata: {}", this.metadataTools.toPath( projectRef ) ); 213 return; 214 } 215 metadataTools.updateMetadata( this.repository, metadataPath ); 216 log.debug( "Updated metadata: {}", this.metadataTools.toPath( projectRef ) ); 217 } 218 catch ( RepositoryMetadataException e ) 219 { 220 log.error( "Unable to write project metadat for artifact [{}]:", path, e ); 221 triggerConsumerError( TYPE_METADATA_WRITE_FAILURE, 222 "Unable to write project metadata for artifact [" + path + "]: " + e.getMessage( ) ); 223 } 224 catch ( IOException e ) 225 { 226 log.warn( "Project metadata not written due to IO warning: ", e ); 227 triggerConsumerWarning( TYPE_METADATA_IO, 228 "Project metadata not written due to IO warning: " + e.getMessage( ) ); 229 } 230 } 231 232 private void updateVersionMetadata( ArtifactReference artifact, String path ) 233 { 234 VersionedReference versionRef = new VersionedReference( ); 235 versionRef.setGroupId( artifact.getGroupId( ) ); 236 versionRef.setArtifactId( artifact.getArtifactId( ) ); 237 versionRef.setVersion( artifact.getVersion( ) ); 238 239 try 240 { 241 String metadataPath = this.metadataTools.toPath( versionRef ); 242 243 Path projectMetadata = this.repositoryDir.resolve( metadataPath ); 244 245 if ( Files.exists(projectMetadata) && ( Files.getLastModifiedTime( projectMetadata ).toMillis() >= this.scanStartTimestamp ) ) 246 { 247 // This metadata is up to date. skip it. 248 log.debug( "Skipping uptodate metadata: {}", this.metadataTools.toPath( versionRef ) ); 249 return; 250 } 251 252 metadataTools.updateMetadata( this.repository, metadataPath ); 253 log.debug( "Updated metadata: {}", this.metadataTools.toPath( versionRef ) ); 254 } 255 catch ( RepositoryMetadataException e ) 256 { 257 log.error( "Unable to write version metadata for artifact [{}]: ", path, e ); 258 triggerConsumerError( TYPE_METADATA_WRITE_FAILURE, 259 "Unable to write version metadata for artifact [" + path + "]: " + e.getMessage( ) ); 260 } 261 catch ( IOException e ) 262 { 263 log.warn( "Version metadata not written due to IO warning: ", e ); 264 triggerConsumerWarning( TYPE_METADATA_IO, 265 "Version metadata not written due to IO warning: " + e.getMessage( ) ); 266 } 267 } 268 269 /* 270 @Override 271 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 272 { 273 if ( ConfigurationNames.isRepositoryScanning( propertyName ) ) 274 { 275 initIncludes(); 276 } 277 } 278 279 @Override 280 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 281 { 282 // do nothing here 283 } 284 */ 285 286 private void initIncludes( ) 287 { 288 includes = new ArrayList<>( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) ); 289 } 290 291 @PostConstruct 292 public void initialize( ) 293 { 294 //configuration.addChangeListener( this ); 295 296 initIncludes( ); 297 } 298}