]> source.dussan.org Git - archiva.git/blob
396b7e3a467dfd7c7b860b31abd73f06d6a20c00
[archiva.git] /
1 package org.apache.maven.archiva.consumers.database;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.maven.archiva.common.utils.VersionUtil;
28 import org.apache.maven.archiva.consumers.AbstractMonitoredConsumer;
29 import org.apache.maven.archiva.consumers.ConsumerException;
30 import org.apache.maven.archiva.database.ArchivaDAO;
31 import org.apache.maven.archiva.database.ArchivaDatabaseException;
32 import org.apache.maven.archiva.database.ObjectNotFoundException;
33 import org.apache.maven.archiva.database.updater.DatabaseUnprocessedArtifactConsumer;
34 import org.apache.maven.archiva.model.ArchivaArtifact;
35 import org.apache.maven.archiva.model.ArchivaModelCloner;
36 import org.apache.maven.archiva.model.ArchivaProjectModel;
37 import org.apache.maven.archiva.model.CiManagement;
38 import org.apache.maven.archiva.model.IssueManagement;
39 import org.apache.maven.archiva.model.Keys;
40 import org.apache.maven.archiva.model.Organization;
41 import org.apache.maven.archiva.model.RepositoryProblem;
42 import org.apache.maven.archiva.reporting.artifact.CorruptArtifactReport;
43 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
44 import org.apache.maven.archiva.repository.RepositoryContentFactory;
45 import org.apache.maven.archiva.repository.RepositoryException;
46 import org.apache.maven.archiva.repository.content.ManagedLegacyRepositoryContent;
47 import org.apache.maven.archiva.repository.project.ProjectModelReader;
48 import org.apache.maven.archiva.repository.project.filters.EffectiveProjectModelFilter;
49 import org.apache.maven.archiva.repository.project.readers.ProjectModel300Reader;
50 import org.apache.maven.archiva.repository.project.readers.ProjectModel400Reader;
51 import org.apache.maven.archiva.xml.XMLException;
52 import org.codehaus.plexus.cache.Cache;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * ProjectModelToDatabaseConsumer
58  *
59  * @version $Id$
60  * @plexus.component role="org.apache.maven.archiva.database.updater.DatabaseUnprocessedArtifactConsumer"
61  * role-hint="update-db-project"
62  * instantiation-strategy="per-lookup"
63  */
64 public class ProjectModelToDatabaseConsumer
65     extends AbstractMonitoredConsumer
66     implements DatabaseUnprocessedArtifactConsumer
67 {
68     private Logger log = LoggerFactory.getLogger( ProjectModelToDatabaseConsumer.class );
69
70     /**
71      * @plexus.configuration default-value="update-db-project"
72      */
73     private String id;
74
75     /**
76      * @plexus.configuration default-value="Update database with project model information."
77      */
78     private String description;
79
80     /**
81      * @plexus.requirement role-hint="jdo"
82      */
83     private ArchivaDAO dao;
84
85     /**
86      * @plexus.requirement
87      */
88     private RepositoryContentFactory repositoryFactory;
89
90     /**
91      * @plexus.requirement role="org.apache.maven.archiva.repository.project.ProjectModelFilter"
92      * role-hint="effective"
93      */
94     private EffectiveProjectModelFilter effectiveModelFilter;
95
96     private List<String> includes;
97
98     /**
99      * @plexus.requirement role-hint="effective-project-cache"
100      */
101     private Cache effectiveProjectCache;
102
103     public ProjectModelToDatabaseConsumer()
104     {
105         includes = new ArrayList<String>();
106         includes.add( "pom" );
107     }
108
109     public void beginScan()
110     {
111         /* nothing to do here */
112     }
113
114     public void completeScan()
115     {
116         /* nothing to do here */
117     }
118
119     public List<String> getIncludedTypes()
120     {
121         return includes;
122     }
123
124     public void processArchivaArtifact( ArchivaArtifact artifact )
125         throws ConsumerException
126     {
127         if ( !StringUtils.equals( "pom", artifact.getType() ) )
128         {
129             // Not a pom.  Skip it.
130             return;
131         }
132         
133         ArchivaProjectModel model = null;
134         
135         // remove old project model if it already exists in the database
136         if ( ( model =
137             getProjectModelFromDatabase( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() ) ) != null )
138         {
139             removeOldProjectModel( model );
140             model = null;
141         }
142
143         ManagedRepositoryContent repo = getRepository( artifact );
144         File artifactFile = repo.toFile( artifact );
145         
146         ProjectModelReader reader;
147         if ( repo instanceof ManagedLegacyRepositoryContent )
148         {
149             reader = new ProjectModel300Reader();
150         }
151         else
152         {
153             reader = new ProjectModel400Reader();
154         }
155
156         try
157         {
158             model = reader.read( artifactFile );
159
160             Organization organization = model.getOrganization();
161             if( organization != null )
162             {
163                 log.info( "++++ [AfterRead] organization NAME --> " + organization.getName() + " : " + organization.getOrganizationName() );
164             }
165             
166             IssueManagement iM = model.getIssueManagement();
167             if( iM != null )
168             {
169                 log.info( "++++ [AfterRead] issueMgnt url --> " + iM.getUrl() + " : " + iM.getIssueManagementUrl() );
170             }
171             
172             CiManagement ci = model.getCiManagement();
173             if( ci != null )
174             {
175                 log.info( "++++ [AfterRead] ci url --> " + ci.getUrl() + " : " + ci.getCiUrl() );
176             }
177             
178             // The version should be updated to the artifact/filename version if it is a unique snapshot
179             if ( VersionUtil.isUniqueSnapshot( artifact.getVersion() ) )
180             {
181                 model.setVersion( artifact.getVersion() );
182             }
183
184             // Resolve the project model (build effective model, resolve expressions)
185             model = effectiveModelFilter.filter( model );
186             
187             organization = model.getOrganization();
188             if( organization != null )
189             {
190                 log.info( "++++ [AfterFilter] organization NAME --> " + organization.getName() + " : " + organization.getOrganizationName() );
191             }
192             
193             iM = model.getIssueManagement();
194             if( iM != null )
195             {
196                 log.info( "++++ [AfterFilter] issueMgnt url --> " + iM.getUrl() + " : " + iM.getIssueManagementUrl() );
197             }
198             
199             ci = model.getCiManagement();
200             if( ci != null )
201             {
202                 log.info( "++++ [AfterFilter] ci url --> " + ci.getUrl() + " : " + ci.getCiUrl() );
203             }
204
205             if ( isValidModel( model, repo, artifact ) )
206             {
207                 log.debug( "Adding project model to database - " + Keys.toKey( model ) );
208                 
209                 // Clone model, since DAO while detachingCopy resets its contents
210                 // This changes contents of the cache in EffectiveProjectModelFilter
211                 model = ArchivaModelCloner.clone( model );
212                 
213                 organization = model.getOrganization();
214                 if( organization != null )
215                 {
216                     log.info( "++++ [AfterClone] organization NAME --> " + organization.getName() + " : " + organization.getOrganizationName() );
217                 }
218                 
219                 iM = model.getIssueManagement();
220                 if( iM != null )
221                 {
222                     log.info( "++++ [AfterClone] issueMgnt url --> " + iM.getUrl() + " : " + iM.getIssueManagementUrl() );
223                 }
224                 
225                 ci = model.getCiManagement();
226                 if( ci != null )
227                 {
228                     log.info( "++++ [AfterClone] ci url --> " + ci.getUrl() + " : " + ci.getCiUrl() );
229                 }
230                 
231                 dao.getProjectModelDAO().saveProjectModel( model );
232             }
233             else
234             {
235                 log.warn( "Invalid or corrupt pom. Project model not added to database - " + Keys.toKey( model ) );
236             }
237
238         }
239         catch ( XMLException e )
240         {
241             log.warn( "Unable to read project model " + artifactFile + " : " + e.getMessage() );
242
243             addProblem( artifact, "Unable to read project model " + artifactFile + " : " + e.getMessage() );
244         }
245         catch ( ArchivaDatabaseException e )
246         {
247             log.warn( "Unable to save project model " + artifactFile + " to the database : " + e.getMessage(), e );
248         }
249         catch ( Throwable t )
250         {
251             // Catch the other errors in the process to allow the rest of the process to complete.
252             log.error( "Unable to process model " + artifactFile + " due to : " + t.getClass().getName() + " : " +
253                 t.getMessage(), t );
254         }
255     }
256
257     private ArchivaProjectModel getProjectModelFromDatabase( String groupId, String artifactId, String version )
258     {
259         try
260         {
261             ArchivaProjectModel model = dao.getProjectModelDAO().getProjectModel( groupId, artifactId, version );
262             return model;
263         }
264         catch ( ObjectNotFoundException e )
265         {
266             return null;
267         }
268         catch ( ArchivaDatabaseException e )
269         {
270             return null;
271         }
272     }
273
274     private ManagedRepositoryContent getRepository( ArchivaArtifact artifact )
275         throws ConsumerException
276     {
277         String repoId = artifact.getModel().getRepositoryId();
278         try
279         {
280             return repositoryFactory.getManagedRepositoryContent( repoId );
281         }
282         catch ( RepositoryException e )
283         {
284             throw new ConsumerException( "Unable to process project model: " + e.getMessage(), e );
285         }
286     }
287
288     public String getDescription()
289     {
290         return description;
291     }
292
293     public String getId()
294     {
295         return id;
296     }
297
298     public boolean isPermanent()
299     {
300         // Tells the configuration that this consumer cannot be disabled.
301         return true;
302     }
303
304     private boolean isValidModel( ArchivaProjectModel model, ManagedRepositoryContent repo, ArchivaArtifact artifact )
305         throws ConsumerException
306     {
307         File artifactFile = repo.toFile( artifact );
308
309         if ( !artifact.getArtifactId().equalsIgnoreCase( model.getArtifactId() ) )
310         {
311             StringBuffer emsg = new StringBuffer();
312             emsg.append( "File " ).append( artifactFile.getName() );
313             emsg.append( " has an invalid project model [" );
314             appendModel( emsg, model );
315             emsg.append( "]: The model artifactId [" ).append( model.getArtifactId() );
316             emsg.append( "] does not match the artifactId portion of the filename: " ).append( artifact.getArtifactId() );
317
318             log.warn( emsg.toString() );
319             addProblem( artifact, emsg.toString() );
320
321             return false;
322         }
323
324         if ( !artifact.getVersion().equalsIgnoreCase( model.getVersion() ) &&
325             !VersionUtil.getBaseVersion( artifact.getVersion() ).equalsIgnoreCase( model.getVersion() ) )
326         {
327             StringBuffer emsg = new StringBuffer();
328             emsg.append( "File " ).append( artifactFile.getName() );
329             emsg.append( " has an invalid project model [" );
330             appendModel( emsg, model );
331             emsg.append( "]; The model version [" ).append( model.getVersion() );
332             emsg.append( "] does not match the version portion of the filename: " ).append( artifact.getVersion() );
333
334             log.warn( emsg.toString() );
335             addProblem( artifact, emsg.toString() );
336
337             return false;
338         }
339
340         return true;
341     }
342
343     private void appendModel( StringBuffer buf, ArchivaProjectModel model )
344     {
345         buf.append( "groupId:" ).append( model.getGroupId() );
346         buf.append( "|artifactId:" ).append( model.getArtifactId() );
347         buf.append( "|version:" ).append( model.getVersion() );
348         buf.append( "|packaging:" ).append( model.getPackaging() );
349     }
350
351     private void addProblem( ArchivaArtifact artifact, String msg )
352         throws ConsumerException
353     {
354         ManagedRepositoryContent repo = getRepository( artifact );
355
356         RepositoryProblem problem = new RepositoryProblem();
357         problem.setRepositoryId( artifact.getModel().getRepositoryId() );
358         problem.setPath( repo.toPath( artifact ) );
359         problem.setGroupId( artifact.getGroupId() );
360         problem.setArtifactId( artifact.getArtifactId() );
361         problem.setVersion( artifact.getVersion() );
362         problem.setType( CorruptArtifactReport.PROBLEM_TYPE_CORRUPT_ARTIFACT );
363         problem.setOrigin( getId() );
364         problem.setMessage( msg );
365
366         try
367         {
368             dao.getRepositoryProblemDAO().saveRepositoryProblem( problem );
369         }
370         catch ( ArchivaDatabaseException e )
371         {
372             String emsg = "Unable to save problem with artifact location to DB: " + e.getMessage();
373             log.warn( emsg, e );
374             throw new ConsumerException( emsg, e );
375         }
376     }
377
378     private String toProjectKey( ArchivaProjectModel project )
379     {
380         StringBuilder key = new StringBuilder();
381
382         key.append( project.getGroupId() ).append( ":" );
383         key.append( project.getArtifactId() ).append( ":" );
384         key.append( project.getVersion() );
385
386         return key.toString();
387     }
388
389     private void removeOldProjectModel( ArchivaProjectModel model )
390     {
391         try
392         {
393             dao.getProjectModelDAO().deleteProjectModel( model );
394         }
395         catch ( ArchivaDatabaseException ae )
396         {
397             log.error( "Unable to delete existing project model." );
398         }
399
400         // Force removal of project model from effective cache
401         String projectKey = toProjectKey( model );
402         synchronized ( effectiveProjectCache )
403         {
404             if ( effectiveProjectCache.hasKey( projectKey ) )
405             {
406                 effectiveProjectCache.remove( projectKey );
407             }
408         }
409     }
410 }