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