001    package org.apache.archiva.configuration;
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.common.FileTypeUtils;
023    import org.apache.archiva.configuration.functors.FiletypeSelectionPredicate;
024    import org.apache.archiva.configuration.io.registry.ConfigurationRegistryReader;
025    import org.apache.archiva.redback.components.registry.Registry;
026    import org.apache.archiva.redback.components.registry.RegistryException;
027    import org.apache.archiva.redback.components.registry.RegistryListener;
028    import org.apache.archiva.redback.components.registry.commons.CommonsConfigurationRegistry;
029    import org.apache.commons.collections.CollectionUtils;
030    import org.apache.commons.collections.Predicate;
031    import org.apache.commons.configuration.CombinedConfiguration;
032    import org.apache.tools.ant.types.selectors.SelectorUtils;
033    import org.springframework.stereotype.Service;
034    
035    import javax.annotation.PostConstruct;
036    import javax.inject.Inject;
037    import javax.inject.Named;
038    import java.lang.reflect.Field;
039    import java.util.ArrayList;
040    import java.util.Collections;
041    import java.util.HashMap;
042    import java.util.List;
043    import java.util.Map;
044    
045    /**
046     * FileTypes
047     */
048    @Service ("fileTypes")
049    public class FileTypes
050        implements RegistryListener
051    {
052        public static final String ARTIFACTS = "artifacts";
053    
054        public static final String AUTO_REMOVE = "auto-remove";
055    
056        public static final String INDEXABLE_CONTENT = "indexable-content";
057    
058        public static final String IGNORED = "ignored";
059    
060        /**
061         *
062         */
063        @Inject
064        @Named (value = "archivaConfiguration#default")
065        private ArchivaConfiguration archivaConfiguration;
066    
067        /**
068         * Map of default values for the file types.
069         */
070        private Map<String, List<String>> defaultTypeMap = new HashMap<String, List<String>>();
071    
072        private List<String> artifactPatterns;
073    
074        /**
075         * Default exclusions from artifact consumers that are using the file types. Note that this is simplistic in the
076         * case of the support files (based on extension) as it is elsewhere - it may be better to match these to actual
077         * artifacts and exclude later during scanning.
078         *
079         * @deprecated
080         */
081        public static final List<String> DEFAULT_EXCLUSIONS = FileTypeUtils.DEFAULT_EXCLUSIONS;
082    
083        public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
084        {
085            this.archivaConfiguration = archivaConfiguration;
086        }
087    
088        /**
089         * <p>
090         * Get the list of patterns for a specified filetype.
091         * </p>
092         * <p/>
093         * <p>
094         * You will always get a list.  In this order.
095         * <ul>
096         * <li>The Configured List</li>
097         * <li>The Default List</li>
098         * <li>A single item list of <code>"**<span>/</span>*"</code></li>
099         * </ul>
100         * </p>
101         *
102         * @param id the id to lookup.
103         * @return the list of patterns.
104         */
105        public List<String> getFileTypePatterns( String id )
106        {
107            Configuration config = archivaConfiguration.getConfiguration();
108            Predicate selectedFiletype = new FiletypeSelectionPredicate( id );
109            RepositoryScanningConfiguration repositoryScanningConfiguration = config.getRepositoryScanning();
110            if ( repositoryScanningConfiguration != null )
111            {
112                FileType filetype =
113                    (FileType) CollectionUtils.find( config.getRepositoryScanning().getFileTypes(), selectedFiletype );
114    
115                if ( ( filetype != null ) && CollectionUtils.isNotEmpty( filetype.getPatterns() ) )
116                {
117                    return filetype.getPatterns();
118                }
119            }
120            List<String> defaultPatterns = defaultTypeMap.get( id );
121    
122            if ( CollectionUtils.isEmpty( defaultPatterns ) )
123            {
124                return Collections.singletonList( "**/*" );
125            }
126    
127            return defaultPatterns;
128        }
129    
130        public synchronized boolean matchesArtifactPattern( String relativePath )
131        {
132            // Correct the slash pattern.
133            relativePath = relativePath.replace( '\\', '/' );
134    
135            if ( artifactPatterns == null )
136            {
137                artifactPatterns = getFileTypePatterns( ARTIFACTS );
138            }
139    
140            for ( String pattern : artifactPatterns )
141            {
142                if ( SelectorUtils.matchPath( pattern, relativePath, false ) )
143                {
144                    // Found match
145                    return true;
146                }
147            }
148    
149            // No match.
150            return false;
151        }
152    
153        public boolean matchesDefaultExclusions( String relativePath )
154        {
155            // Correct the slash pattern.
156            relativePath = relativePath.replace( '\\', '/' );
157    
158            for ( String pattern : DEFAULT_EXCLUSIONS )
159            {
160                if ( SelectorUtils.matchPath( pattern, relativePath, false ) )
161                {
162                    // Found match
163                    return true;
164                }
165            }
166    
167            // No match.
168            return false;
169        }
170    
171        @PostConstruct
172        public void initialize()
173        {
174            // TODO: why is this done by hand?
175    
176            // TODO: ideally, this would be instantiated by configuration instead, and not need to be a component
177    
178            String errMsg = "Unable to load default archiva configuration for FileTypes: ";
179    
180            try
181            {
182                CommonsConfigurationRegistry commonsRegistry = new CommonsConfigurationRegistry();
183    
184                // Configure commonsRegistry
185                Field fld = commonsRegistry.getClass().getDeclaredField( "configuration" );
186                fld.setAccessible( true );
187                fld.set( commonsRegistry, new CombinedConfiguration() );
188                commonsRegistry.addConfigurationFromResource( "org/apache/archiva/configuration/default-archiva.xml" );
189    
190                // Read configuration as it was intended.
191                ConfigurationRegistryReader configReader = new ConfigurationRegistryReader();
192                Configuration defaultConfig = configReader.read( commonsRegistry );
193    
194                initialiseTypeMap( defaultConfig );
195            }
196            catch ( RegistryException e )
197            {
198                throw new RuntimeException( errMsg + e.getMessage(), e );
199            }
200            catch ( SecurityException e )
201            {
202                throw new RuntimeException( errMsg + e.getMessage(), e );
203            }
204            catch ( NoSuchFieldException e )
205            {
206                throw new RuntimeException( errMsg + e.getMessage(), e );
207            }
208            catch ( IllegalArgumentException e )
209            {
210                throw new RuntimeException( errMsg + e.getMessage(), e );
211            }
212            catch ( IllegalAccessException e )
213            {
214                throw new RuntimeException( errMsg + e.getMessage(), e );
215            }
216    
217            this.archivaConfiguration.addChangeListener( this );
218        }
219    
220        private void initialiseTypeMap( Configuration configuration )
221        {
222            defaultTypeMap.clear();
223    
224            // Store the default file type declaration.
225            List<FileType> filetypes = configuration.getRepositoryScanning().getFileTypes();
226            for ( FileType filetype : filetypes )
227            {
228                List<String> patterns = defaultTypeMap.get( filetype.getId() );
229                if ( patterns == null )
230                {
231                    patterns = new ArrayList<String>( filetype.getPatterns().size() );
232                }
233                patterns.addAll( filetype.getPatterns() );
234    
235                defaultTypeMap.put( filetype.getId(), patterns );
236            }
237        }
238    
239        public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
240        {
241            if ( propertyName.contains( "fileType" ) )
242            {
243                artifactPatterns = null;
244    
245                initialiseTypeMap( archivaConfiguration.getConfiguration() );
246            }
247        }
248    
249        public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
250        {
251            /* nothing to do */
252        }
253    }