001    package org.apache.archiva.scheduler.repository;
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.RepositoryAdminException;
023    import org.apache.archiva.admin.model.beans.ManagedRepository;
024    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
025    import org.apache.archiva.metadata.repository.MetadataRepository;
026    import org.apache.archiva.metadata.repository.MetadataRepositoryException;
027    import org.apache.archiva.metadata.repository.RepositorySession;
028    import org.apache.archiva.metadata.repository.RepositorySessionFactory;
029    import org.apache.archiva.metadata.repository.stats.RepositoryStatistics;
030    import org.apache.archiva.metadata.repository.stats.RepositoryStatisticsManager;
031    import org.apache.archiva.repository.scanner.RepositoryContentConsumers;
032    import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
033    import org.apache.archiva.repository.scanner.RepositoryScanner;
034    import org.apache.archiva.repository.scanner.RepositoryScannerException;
035    import org.apache.archiva.scheduler.repository.model.RepositoryTask;
036    import org.apache.commons.lang.StringUtils;
037    import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
038    import org.apache.archiva.redback.components.taskqueue.Task;
039    import org.apache.archiva.redback.components.taskqueue.execution.TaskExecutionException;
040    import org.apache.archiva.redback.components.taskqueue.execution.TaskExecutor;
041    import org.slf4j.Logger;
042    import org.slf4j.LoggerFactory;
043    import org.springframework.stereotype.Service;
044    
045    import javax.annotation.PostConstruct;
046    import javax.inject.Inject;
047    import java.util.Date;
048    
049    /**
050     * ArchivaRepositoryScanningTaskExecutor
051     *
052     *
053     */
054    @Service( "taskExecutor#repository-scanning" )
055    public class ArchivaRepositoryScanningTaskExecutor
056        implements TaskExecutor
057    {
058        private Logger log = LoggerFactory.getLogger( ArchivaRepositoryScanningTaskExecutor.class );
059    
060        /**
061         *
062         */
063        @Inject
064        private ManagedRepositoryAdmin managedRepositoryAdmin;
065    
066        /**
067         * The repository scanner component.
068         */
069        @Inject
070        private RepositoryScanner repoScanner;
071    
072        /**
073         *
074         */
075        @Inject
076        private RepositoryContentConsumers consumers;
077    
078        private Task task;
079    
080        /**
081         *
082         */
083        @Inject
084        private RepositoryStatisticsManager repositoryStatisticsManager;
085    
086        /**
087         * FIXME: this could be multiple implementations and needs to be configured.
088         */
089        @Inject
090        private RepositorySessionFactory repositorySessionFactory;
091    
092        @PostConstruct
093        public void initialize()
094            throws InitializationException
095        {
096            log.info( "Initialized {}", this.getClass().getName() );
097        }
098    
099        @SuppressWarnings( "unchecked" )
100        public void executeTask( Task task )
101            throws TaskExecutionException
102        {
103            try
104            {
105                // TODO: replace this whole class with the prescribed content scanning service/action
106                // - scan repository for artifacts that do not have corresponding metadata or have been updated and
107                // send events for each
108                // - scan metadata for artifacts that have been removed and send events for each
109                // - scan metadata for missing plugin data
110                // - store information so that it can restart upon failure (publish event on the server recovery
111                // queue, remove it on successful completion)
112    
113                this.task = task;
114    
115                RepositoryTask repoTask = (RepositoryTask) task;
116    
117                String repoId = repoTask.getRepositoryId();
118                if ( StringUtils.isBlank( repoId ) )
119                {
120                    throw new TaskExecutionException( "Unable to execute RepositoryTask with blank repository Id." );
121                }
122    
123                ManagedRepository arepo = managedRepositoryAdmin.getManagedRepository( repoId );
124    
125                // execute consumers on resource file if set
126                if ( repoTask.getResourceFile() != null )
127                {
128                    log.debug( "Executing task from queue with job name: {}", repoTask );
129                    consumers.executeConsumers( arepo, repoTask.getResourceFile(), repoTask.isUpdateRelatedArtifacts() );
130                }
131                else
132                {
133                    log.info( "Executing task from queue with job name: {}", repoTask );
134    
135                    // otherwise, execute consumers on whole repository
136                    if ( arepo == null )
137                    {
138                        throw new TaskExecutionException(
139                            "Unable to execute RepositoryTask with invalid repository id: " + repoId );
140                    }
141    
142                    long sinceWhen = RepositoryScanner.FRESH_SCAN;
143                    long previousFileCount = 0;
144    
145                    RepositorySession repositorySession = repositorySessionFactory.createSession();
146                    MetadataRepository metadataRepository = repositorySession.getRepository();
147                    try
148                    {
149                        if ( !repoTask.isScanAll() )
150                        {
151                            RepositoryStatistics previousStats =
152                                repositoryStatisticsManager.getLastStatistics( metadataRepository, repoId );
153                            if ( previousStats != null )
154                            {
155                                sinceWhen = previousStats.getScanStartTime().getTime();
156                                previousFileCount = previousStats.getTotalFileCount();
157                            }
158                        }
159    
160                        RepositoryScanStatistics stats;
161                        try
162                        {
163                            stats = repoScanner.scan( arepo, sinceWhen );
164                        }
165                        catch ( RepositoryScannerException e )
166                        {
167                            throw new TaskExecutionException( "Repository error when executing repository job.", e );
168                        }
169    
170                        log.info( "Finished first scan: {}", stats.toDump( arepo ) );
171    
172                        // further statistics will be populated by the following method
173                        Date endTime = new Date( stats.getWhenGathered().getTime() + stats.getDuration() );
174    
175                        log.info( "Gathering repository statistics" );
176    
177                        repositoryStatisticsManager.addStatisticsAfterScan( metadataRepository, repoId,
178                                                                            stats.getWhenGathered(), endTime,
179                                                                            stats.getTotalFileCount(),
180                                                                            stats.getTotalFileCount() - previousFileCount );
181                        repositorySession.save();
182                    }
183                    catch ( MetadataRepositoryException e )
184                    {
185                        throw new TaskExecutionException( "Unable to store updated statistics: " + e.getMessage(), e );
186                    }
187                    finally
188                    {
189                        repositorySession.close();
190                    }
191    
192    //                log.info( "Scanning for removed repository content" );
193    
194    //                metadataRepository.findAllProjects();
195                    // FIXME: do something
196    
197                    log.info( "Finished repository task: {}", repoTask );
198    
199                    this.task = null;
200                }
201            }
202            catch ( RepositoryAdminException e )
203            {
204                log.error( e.getMessage(), e );
205                throw new TaskExecutionException( e.getMessage(), e );
206            }
207        }
208    
209        public Task getCurrentTaskInExecution()
210        {
211            return task;
212        }
213    
214        public RepositoryScanner getRepoScanner()
215        {
216            return repoScanner;
217        }
218    
219        public void setRepoScanner( RepositoryScanner repoScanner )
220        {
221            this.repoScanner = repoScanner;
222        }
223    
224        public RepositoryContentConsumers getConsumers()
225        {
226            return consumers;
227        }
228    
229        public void setConsumers( RepositoryContentConsumers consumers )
230        {
231            this.consumers = consumers;
232        }
233    
234        public RepositorySessionFactory getRepositorySessionFactory()
235        {
236            return repositorySessionFactory;
237        }
238    
239        public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
240        {
241            this.repositorySessionFactory = repositorySessionFactory;
242        }
243    
244        public RepositoryStatisticsManager getRepositoryStatisticsManager()
245        {
246            return repositoryStatisticsManager;
247        }
248    
249        public void setRepositoryStatisticsManager( RepositoryStatisticsManager repositoryStatisticsManager )
250        {
251            this.repositoryStatisticsManager = repositoryStatisticsManager;
252        }
253    
254        public ManagedRepositoryAdmin getManagedRepositoryAdmin()
255        {
256            return managedRepositoryAdmin;
257        }
258    
259        public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
260        {
261            this.managedRepositoryAdmin = managedRepositoryAdmin;
262        }
263    }