001    package org.apache.archiva.repository.scanner;
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.admin.ArchivaAdministration;
024    import org.apache.archiva.admin.model.beans.ManagedRepository;
025    import org.apache.archiva.common.utils.BaseFile;
026    import org.apache.archiva.consumers.InvalidRepositoryContentConsumer;
027    import org.apache.archiva.consumers.KnownRepositoryContentConsumer;
028    import org.apache.archiva.consumers.functors.ConsumerWantsFilePredicate;
029    import org.apache.archiva.repository.scanner.functors.ConsumerProcessFileClosure;
030    import org.apache.archiva.repository.scanner.functors.TriggerBeginScanClosure;
031    import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure;
032    import org.apache.commons.collections.Closure;
033    import org.apache.commons.collections.CollectionUtils;
034    import org.apache.commons.collections.functors.IfClosure;
035    import org.springframework.beans.BeansException;
036    import org.springframework.context.ApplicationContext;
037    import org.springframework.context.ApplicationContextAware;
038    import org.springframework.stereotype.Service;
039    
040    import javax.inject.Inject;
041    import java.io.File;
042    import java.util.ArrayList;
043    import java.util.Date;
044    import java.util.HashMap;
045    import java.util.List;
046    import java.util.Map;
047    
048    /**
049     * RepositoryContentConsumerUtil
050     */
051    @Service ("repositoryContentConsumers")
052    public class RepositoryContentConsumers
053        implements ApplicationContextAware
054    {
055    
056        @Inject
057        private ApplicationContext applicationContext;
058    
059        private ArchivaAdministration archivaAdministration;
060    
061        private List<KnownRepositoryContentConsumer> selectedKnownConsumers;
062    
063        private List<InvalidRepositoryContentConsumer> selectedInvalidConsumers;
064    
065        @Inject
066        public RepositoryContentConsumers( ArchivaAdministration archivaAdministration )
067        {
068            this.archivaAdministration = archivaAdministration;
069        }
070    
071        public void setApplicationContext( ApplicationContext applicationContext )
072            throws BeansException
073        {
074            this.applicationContext = applicationContext;
075        }
076    
077        /**
078         * <p>
079         * Get the list of Ids associated with those {@link KnownRepositoryContentConsumer} that have
080         * been selected in the configuration to execute.
081         * </p>
082         * <p/>
083         * <p>
084         * NOTE: This list can be larger and contain entries that might not exist or be available
085         * in the classpath, or as a component.
086         * </p>
087         *
088         * @return the list of consumer ids that have been selected by the configuration.
089         */
090        public List<String> getSelectedKnownConsumerIds()
091            throws RepositoryAdminException
092        {
093            return archivaAdministration.getKnownContentConsumers();
094        }
095    
096        /**
097         * <p>
098         * Get the list of Ids associated with those {@link InvalidRepositoryContentConsumer} that have
099         * been selected in the configuration to execute.
100         * </p>
101         * <p/>
102         * <p>
103         * NOTE: This list can be larger and contain entries that might not exist or be available
104         * in the classpath, or as a component.
105         * </p>
106         *
107         * @return the list of consumer ids that have been selected by the configuration.
108         */
109        public List<String> getSelectedInvalidConsumerIds()
110            throws RepositoryAdminException
111        {
112            return archivaAdministration.getInvalidContentConsumers();
113        }
114    
115        /**
116         * Get the map of {@link String} ids to {@link KnownRepositoryContentConsumer} implementations,
117         * for those consumers that have been selected according to the active configuration.
118         *
119         * @return the map of String ids to {@link KnownRepositoryContentConsumer} objects.
120         */
121        public Map<String, KnownRepositoryContentConsumer> getSelectedKnownConsumersMap()
122            throws RepositoryAdminException
123        {
124            Map<String, KnownRepositoryContentConsumer> consumerMap = new HashMap<String, KnownRepositoryContentConsumer>();
125    
126            for ( KnownRepositoryContentConsumer consumer : getSelectedKnownConsumers() )
127            {
128                consumerMap.put( consumer.getId(), consumer );
129            }
130    
131            return consumerMap;
132        }
133    
134        /**
135         * Get the map of {@link String} ids to {@link InvalidRepositoryContentConsumer} implementations,
136         * for those consumers that have been selected according to the active configuration.
137         *
138         * @return the map of String ids to {@link InvalidRepositoryContentConsumer} objects.
139         */
140        public Map<String, InvalidRepositoryContentConsumer> getSelectedInvalidConsumersMap()
141            throws RepositoryAdminException
142        {
143            Map<String, InvalidRepositoryContentConsumer> consumerMap =
144                new HashMap<String, InvalidRepositoryContentConsumer>();
145    
146            for ( InvalidRepositoryContentConsumer consumer : getSelectedInvalidConsumers() )
147            {
148                consumerMap.put( consumer.getId(), consumer );
149            }
150    
151            return consumerMap;
152        }
153    
154        /**
155         * Get the list of {@link KnownRepositoryContentConsumer} objects that are
156         * selected according to the active configuration.
157         *
158         * @return the list of {@link KnownRepositoryContentConsumer} that have been selected
159         *         by the active configuration.
160         */
161        public synchronized List<KnownRepositoryContentConsumer> getSelectedKnownConsumers()
162            throws RepositoryAdminException
163        {
164            // FIXME only for testing
165            if ( selectedKnownConsumers != null )
166            {
167                return selectedKnownConsumers;
168            }
169            List<KnownRepositoryContentConsumer> ret = new ArrayList<KnownRepositoryContentConsumer>();
170    
171            List<String> knownSelected = getSelectedKnownConsumerIds();
172    
173            for ( KnownRepositoryContentConsumer consumer : getAvailableKnownConsumers() )
174            {
175                if ( knownSelected.contains( consumer.getId() ) || consumer.isPermanent() )
176                {
177                    ret.add( consumer );
178                }
179            }
180            return ret;
181        }
182    
183        /**
184         * Get the list of {@link InvalidRepositoryContentConsumer} objects that are
185         * selected according to the active configuration.
186         *
187         * @return the list of {@link InvalidRepositoryContentConsumer} that have been selected
188         *         by the active configuration.
189         */
190        public synchronized List<InvalidRepositoryContentConsumer> getSelectedInvalidConsumers()
191            throws RepositoryAdminException
192        {
193    
194            // FIXME only for testing
195            if ( selectedInvalidConsumers != null )
196            {
197                return selectedInvalidConsumers;
198            }
199    
200            List<InvalidRepositoryContentConsumer> ret = new ArrayList<InvalidRepositoryContentConsumer>();
201    
202            List<String> invalidSelected = getSelectedInvalidConsumerIds();
203    
204            for ( InvalidRepositoryContentConsumer consumer : getAvailableInvalidConsumers() )
205            {
206                if ( invalidSelected.contains( consumer.getId() ) || consumer.isPermanent() )
207                {
208                    ret.add( consumer );
209                }
210            }
211            return ret;
212        }
213    
214    
215        /**
216         * Get the list of {@link KnownRepositoryContentConsumer} objects that are
217         * available and present in the classpath and as components in the IoC.
218         *
219         * @return the list of all available {@link KnownRepositoryContentConsumer} present in the classpath
220         *         and as a component in the IoC.
221         */
222        public List<KnownRepositoryContentConsumer> getAvailableKnownConsumers()
223        {
224            return new ArrayList<KnownRepositoryContentConsumer>(
225                applicationContext.getBeansOfType( KnownRepositoryContentConsumer.class ).values() );
226        }
227    
228        /**
229         * Get the list of {@link InvalidRepositoryContentConsumer} objects that are
230         * available and present in the classpath and as components in the IoC.
231         *
232         * @return the list of all available {@link InvalidRepositoryContentConsumer} present in the classpath
233         *         and as a component in the IoC.
234         */
235        public List<InvalidRepositoryContentConsumer> getAvailableInvalidConsumers()
236        {
237            return new ArrayList<InvalidRepositoryContentConsumer>(
238                applicationContext.getBeansOfType( InvalidRepositoryContentConsumer.class ).values() );
239        }
240    
241        /**
242         * A convienence method to execute all of the active selected consumers for a
243         * particular arbitrary file.
244         * NOTE: Make sure that there is no repository scanning task executing before invoking this so as to prevent
245         * the index writer/reader of the current index-content consumer executing from getting closed. For an example,
246         * see ArchivaDavResource#executeConsumers( File ).
247         *
248         * @param repository             the repository configuration to use.
249         * @param localFile              the local file to execute the consumers against.
250         * @param updateRelatedArtifacts TODO
251         */
252        public void executeConsumers( ManagedRepository repository, File localFile, boolean updateRelatedArtifacts )
253            throws RepositoryAdminException
254        {
255            // Run the repository consumers
256            try
257            {
258                Closure triggerBeginScan = new TriggerBeginScanClosure( repository, getStartTime(), false );
259    
260                List<KnownRepositoryContentConsumer> selectedKnownConsumers = getSelectedKnownConsumers();
261    
262                // MRM-1212/MRM-1197 
263                // - do not create missing/fix invalid checksums and update metadata when deploying from webdav since these are uploaded by maven
264                if ( !updateRelatedArtifacts )
265                {
266                    List<KnownRepositoryContentConsumer> clone = new ArrayList<KnownRepositoryContentConsumer>();
267                    clone.addAll( selectedKnownConsumers );
268    
269                    for ( KnownRepositoryContentConsumer consumer : clone )
270                    {
271                        if ( consumer.getId().equals( "create-missing-checksums" ) || consumer.getId().equals(
272                            "metadata-updater" ) )
273                        {
274                            selectedKnownConsumers.remove( consumer );
275                        }
276                    }
277                }
278    
279                List<InvalidRepositoryContentConsumer> selectedInvalidConsumers = getSelectedInvalidConsumers();
280                CollectionUtils.forAllDo( selectedKnownConsumers, triggerBeginScan );
281                CollectionUtils.forAllDo( selectedInvalidConsumers, triggerBeginScan );
282    
283                // yuck. In case you can't read this, it says
284                // "process the file if the consumer has it in the includes list, and not in the excludes list"
285                BaseFile baseFile = new BaseFile( repository.getLocation(), localFile );
286                ConsumerWantsFilePredicate predicate = new ConsumerWantsFilePredicate();
287                predicate.setBasefile( baseFile );
288                predicate.setCaseSensitive( false );
289    
290                ConsumerProcessFileClosure closure = new ConsumerProcessFileClosure();
291                closure.setBasefile( baseFile );
292                closure.setExecuteOnEntireRepo( false );
293    
294                Closure processIfWanted = IfClosure.getInstance( predicate, closure );
295    
296                CollectionUtils.forAllDo( selectedKnownConsumers, processIfWanted );
297    
298                if ( predicate.getWantedFileCount() <= 0 )
299                {
300                    // Nothing known processed this file.  It is invalid!
301                    CollectionUtils.forAllDo( selectedInvalidConsumers, closure );
302                }
303    
304                TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure( repository, false );
305    
306                CollectionUtils.forAllDo( selectedKnownConsumers, scanCompletedClosure );
307            }
308            finally
309            {
310                /* TODO: This is never called by the repository scanner instance, so not calling here either - but it probably should be?
311                            CollectionUtils.forAllDo( availableKnownConsumers, triggerCompleteScan );
312                            CollectionUtils.forAllDo( availableInvalidConsumers, triggerCompleteScan );
313                */
314            }
315        }
316    
317        public void setSelectedKnownConsumers( List<KnownRepositoryContentConsumer> selectedKnownConsumers )
318        {
319            this.selectedKnownConsumers = selectedKnownConsumers;
320        }
321    
322        public void setSelectedInvalidConsumers( List<InvalidRepositoryContentConsumer> selectedInvalidConsumers )
323        {
324            this.selectedInvalidConsumers = selectedInvalidConsumers;
325        }
326    
327        protected Date getStartTime()
328        {
329            return new Date( System.currentTimeMillis() );
330        }
331    
332        public void setArchivaAdministration( ArchivaAdministration archivaAdministration )
333        {
334            this.archivaAdministration = archivaAdministration;
335        }
336    }