001 package org.apache.archiva.consumers.metadata; 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 022 import org.apache.archiva.admin.model.beans.ManagedRepository; 023 import org.apache.archiva.common.utils.VersionUtil; 024 import org.apache.archiva.configuration.ArchivaConfiguration; 025 import org.apache.archiva.configuration.ConfigurationNames; 026 import org.apache.archiva.configuration.FileTypes; 027 import org.apache.archiva.consumers.AbstractMonitoredConsumer; 028 import org.apache.archiva.consumers.ConsumerException; 029 import org.apache.archiva.consumers.KnownRepositoryContentConsumer; 030 import org.apache.archiva.metadata.model.ArtifactMetadata; 031 import org.apache.archiva.metadata.model.ProjectMetadata; 032 import org.apache.archiva.metadata.model.ProjectVersionMetadata; 033 import org.apache.archiva.metadata.repository.MetadataRepository; 034 import org.apache.archiva.metadata.repository.MetadataRepositoryException; 035 import org.apache.archiva.metadata.repository.RepositorySession; 036 import org.apache.archiva.metadata.repository.RepositorySessionFactory; 037 import org.apache.archiva.metadata.repository.storage.ReadMetadataRequest; 038 import org.apache.archiva.metadata.repository.storage.RepositoryStorage; 039 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException; 040 import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException; 041 import org.apache.archiva.metadata.repository.storage.RepositoryStorageRuntimeException; 042 import org.apache.archiva.redback.components.registry.Registry; 043 import org.apache.archiva.redback.components.registry.RegistryListener; 044 import org.slf4j.Logger; 045 import org.slf4j.LoggerFactory; 046 import org.springframework.context.annotation.Scope; 047 import org.springframework.stereotype.Service; 048 049 import javax.annotation.PostConstruct; 050 import javax.inject.Inject; 051 import javax.inject.Named; 052 import java.util.ArrayList; 053 import java.util.Date; 054 import java.util.List; 055 056 /** 057 * Take an artifact off of disk and put it into the metadata repository. 058 */ 059 @Service ("knownRepositoryContentConsumer#create-archiva-metadata") 060 @Scope ("prototype") 061 public class ArchivaMetadataCreationConsumer 062 extends AbstractMonitoredConsumer 063 implements KnownRepositoryContentConsumer, RegistryListener 064 { 065 /** 066 * default-value="create-archiva-metadata" 067 */ 068 private String id = "create-archiva-metadata"; 069 070 /** 071 * default-value="Create basic metadata for Archiva to be able to reference the artifact" 072 */ 073 private String description = "Create basic metadata for Archiva to be able to reference the artifact"; 074 075 /** 076 */ 077 @Inject 078 private ArchivaConfiguration configuration; 079 080 /** 081 */ 082 @Inject 083 private FileTypes filetypes; 084 085 private Date whenGathered; 086 087 private List<String> includes = new ArrayList<String>( 0 ); 088 089 /** 090 * FIXME: this could be multiple implementations and needs to be configured. 091 */ 092 @Inject 093 private RepositorySessionFactory repositorySessionFactory; 094 095 /** 096 * FIXME: this needs to be configurable based on storage type - and could also be instantiated per repo. Change to a 097 * factory. 098 */ 099 @Inject 100 @Named (value = "repositoryStorage#maven2") 101 private RepositoryStorage repositoryStorage; 102 103 private static final Logger log = LoggerFactory.getLogger( ArchivaMetadataCreationConsumer.class ); 104 105 private String repoId; 106 107 public String getId() 108 { 109 return this.id; 110 } 111 112 public String getDescription() 113 { 114 return this.description; 115 } 116 117 public boolean isPermanent() 118 { 119 return true; 120 } 121 122 public List<String> getExcludes() 123 { 124 return getDefaultArtifactExclusions(); 125 } 126 127 public List<String> getIncludes() 128 { 129 return this.includes; 130 } 131 132 public void beginScan( ManagedRepository repo, Date whenGathered ) 133 throws ConsumerException 134 { 135 repoId = repo.getId(); 136 this.whenGathered = whenGathered; 137 } 138 139 public void beginScan( ManagedRepository repository, Date whenGathered, boolean executeOnEntireRepo ) 140 throws ConsumerException 141 { 142 beginScan( repository, whenGathered ); 143 } 144 145 public void processFile( String path ) 146 throws ConsumerException 147 { 148 149 RepositorySession repositorySession = repositorySessionFactory.createSession(); 150 try 151 { 152 // note that we do minimal processing including checksums and POM information for performance of 153 // the initial scan. Any request for this information will be intercepted and populated on-demand 154 // or picked up by subsequent scans 155 156 ArtifactMetadata artifact = repositoryStorage.readArtifactMetadataFromPath( repoId, path ); 157 158 ProjectMetadata project = new ProjectMetadata(); 159 project.setNamespace( artifact.getNamespace() ); 160 project.setId( artifact.getProject() ); 161 162 String projectVersion = VersionUtil.getBaseVersion( artifact.getVersion() ); 163 164 MetadataRepository metadataRepository = repositorySession.getRepository(); 165 166 boolean createVersionMetadata = false; 167 168 // FIXME: maybe not too efficient since it may have already been read and stored for this artifact 169 ProjectVersionMetadata versionMetadata = null; 170 try 171 { 172 ReadMetadataRequest readMetadataRequest = 173 new ReadMetadataRequest().repositoryId( repoId ).namespace( artifact.getNamespace() ).projectId( 174 artifact.getProject() ).projectVersion( projectVersion ); 175 versionMetadata = repositoryStorage.readProjectVersionMetadata( readMetadataRequest ); 176 createVersionMetadata = true; 177 } 178 catch ( RepositoryStorageMetadataNotFoundException e ) 179 { 180 log.warn( "Missing or invalid POM for artifact:{} (repository:{}); creating empty metadata", path, 181 repoId ); 182 183 versionMetadata = new ProjectVersionMetadata(); 184 versionMetadata.setId( projectVersion ); 185 versionMetadata.setIncomplete( true ); 186 createVersionMetadata = true; 187 } 188 catch ( RepositoryStorageMetadataInvalidException e ) 189 { 190 log.warn( "Error occurred resolving POM for artifact:{} (repository:{}); message: {}", 191 new Object[]{ path, repoId, e.getMessage() } ); 192 } 193 194 // read the metadata and update it if it is newer or doesn't exist 195 artifact.setWhenGathered( whenGathered ); 196 metadataRepository.updateArtifact( repoId, project.getNamespace(), project.getId(), projectVersion, 197 artifact ); 198 if ( createVersionMetadata ) 199 { 200 metadataRepository.updateProjectVersion( repoId, project.getNamespace(), project.getId(), 201 versionMetadata ); 202 } 203 metadataRepository.updateProject( repoId, project ); 204 repositorySession.save(); 205 } 206 catch ( MetadataRepositoryException e ) 207 { 208 log.warn( 209 "Error occurred persisting metadata for artifact:{} (repository:{}); message: {}" + e.getMessage(), 210 new Object[]{ path, repoId, e.getMessage() }, e ); 211 repositorySession.revert(); 212 } 213 catch ( RepositoryStorageRuntimeException e ) 214 { 215 log.warn( 216 "Error occurred persisting metadata for artifact:{} (repository:{}); message: {}" + e.getMessage(), 217 new Object[]{ path, repoId, e.getMessage() }, e ); 218 repositorySession.revert(); 219 } 220 finally 221 { 222 repositorySession.close(); 223 } 224 } 225 226 public void processFile( String path, boolean executeOnEntireRepo ) 227 throws ConsumerException 228 { 229 processFile( path ); 230 } 231 232 public void completeScan() 233 { 234 /* do nothing */ 235 } 236 237 public void completeScan( boolean executeOnEntireRepo ) 238 { 239 completeScan(); 240 } 241 242 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 243 { 244 if ( ConfigurationNames.isRepositoryScanning( propertyName ) ) 245 { 246 initIncludes(); 247 } 248 } 249 250 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue ) 251 { 252 /* do nothing */ 253 } 254 255 private void initIncludes() 256 { 257 includes = new ArrayList<String>( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) ); 258 } 259 260 @PostConstruct 261 public void initialize() 262 { 263 configuration.addChangeListener( this ); 264 265 initIncludes(); 266 } 267 }