001    package org.apache.archiva.repository.content.maven2;
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.beans.ManagedRepository;
023    import org.apache.archiva.common.utils.PathUtil;
024    import org.apache.archiva.configuration.FileTypes;
025    import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
026    import org.apache.archiva.model.ArchivaArtifact;
027    import org.apache.archiva.model.ArtifactReference;
028    import org.apache.archiva.model.ProjectReference;
029    import org.apache.archiva.model.VersionedReference;
030    import org.apache.archiva.repository.ContentNotFoundException;
031    import org.apache.archiva.repository.ManagedRepositoryContent;
032    import org.apache.archiva.repository.RepositoryException;
033    import org.apache.archiva.repository.layout.LayoutException;
034    import org.apache.commons.io.FileUtils;
035    import org.apache.commons.lang.StringUtils;
036    import org.springframework.context.annotation.Scope;
037    import org.springframework.stereotype.Service;
038    
039    import javax.inject.Inject;
040    import javax.inject.Named;
041    import java.io.File;
042    import java.io.IOException;
043    import java.util.Collections;
044    import java.util.HashSet;
045    import java.util.Set;
046    
047    /**
048     * ManagedDefaultRepositoryContent
049     */
050    @Service ("managedRepositoryContent#default")
051    @Scope ("prototype")
052    public class ManagedDefaultRepositoryContent
053        extends AbstractDefaultRepositoryContent
054        implements ManagedRepositoryContent
055    {
056        @Inject
057        @Named (value = "fileTypes")
058        private FileTypes filetypes;
059    
060        private ManagedRepository repository;
061    
062        public ManagedDefaultRepositoryContent()
063        {
064            // default to use if there are none supplied as components
065            this.artifactMappingProviders = Collections.singletonList( new DefaultArtifactMappingProvider() );
066        }
067    
068        public void deleteVersion( VersionedReference reference )
069        {
070            String path = toMetadataPath( reference );
071            File projectPath = new File( getRepoRoot(), path );
072    
073            File projectDir = projectPath.getParentFile();
074            if ( projectDir.exists() && projectDir.isDirectory() )
075            {
076                FileUtils.deleteQuietly( projectDir );
077            }
078        }
079    
080        public void deleteProject( String namespace, String projectId )
081            throws RepositoryException, ContentNotFoundException
082        {
083            ArtifactReference artifactReference = new ArtifactReference();
084            artifactReference.setGroupId( namespace );
085            artifactReference.setArtifactId( projectId );
086            String path = toPath( artifactReference );
087            File directory = new File( getRepoRoot(), path );
088            if ( !directory.exists() )
089            {
090                throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
091            }
092            if ( directory.isDirectory() )
093            {
094                try
095                {
096                    FileUtils.deleteDirectory( directory );
097                }
098                catch ( IOException e )
099                {
100                    throw new RepositoryException( e.getMessage(), e );
101                }
102            }
103            else
104            {
105                log.warn( "project {}:{} is not a directory", namespace, projectId );
106            }
107    
108        }
109    
110        public void deleteArtifact( ArtifactReference artifactReference )
111        {
112            String path = toPath( artifactReference );
113            File filePath = new File( getRepoRoot(), path );
114    
115            if ( filePath.exists() )
116            {
117                FileUtils.deleteQuietly( filePath );
118            }
119    
120            File filePathmd5 = new File( getRepoRoot(), path + ".md5" );
121    
122            if ( filePathmd5.exists() )
123            {
124                FileUtils.deleteQuietly( filePathmd5 );
125            }
126    
127            File filePathsha1 = new File( getRepoRoot(), path + ".sha1" );
128    
129            if ( filePathsha1.exists() )
130            {
131                FileUtils.deleteQuietly( filePathsha1 );
132            }
133        }
134    
135        public void deleteGroupId( String groupId )
136            throws ContentNotFoundException
137        {
138    
139            String path = StringUtils.replaceChars( groupId, '.', '/' );
140    
141            File directory = new File( getRepoRoot(), path );
142    
143            if ( directory.exists() )
144            {
145                try
146                {
147                    FileUtils.deleteDirectory( directory );
148                }
149                catch ( IOException e )
150                {
151                    log.warn( "skip error deleting directory {}:", directory.getPath(), e );
152                }
153            }
154        }
155    
156        public String getId()
157        {
158            return repository.getId();
159        }
160    
161        public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
162            throws ContentNotFoundException
163        {
164            File artifactFile = toFile( reference );
165            File repoDir = artifactFile.getParentFile();
166    
167            if ( !repoDir.exists() )
168            {
169                throw new ContentNotFoundException(
170                    "Unable to get related artifacts using a non-existant directory: " + repoDir.getAbsolutePath() );
171            }
172    
173            if ( !repoDir.isDirectory() )
174            {
175                throw new ContentNotFoundException(
176                    "Unable to get related artifacts using a non-directory: " + repoDir.getAbsolutePath() );
177            }
178    
179            Set<ArtifactReference> foundArtifacts = new HashSet<ArtifactReference>();
180    
181            // First gather up the versions found as artifacts in the managed repository.
182            File repoFiles[] = repoDir.listFiles();
183            for ( int i = 0; i < repoFiles.length; i++ )
184            {
185                if ( repoFiles[i].isDirectory() )
186                {
187                    // Skip it. it's a directory.
188                    continue;
189                }
190    
191                String relativePath = PathUtil.getRelative( repository.getLocation(), repoFiles[i] );
192    
193                if ( filetypes.matchesArtifactPattern( relativePath ) )
194                {
195                    try
196                    {
197                        ArtifactReference artifact = toArtifactReference( relativePath );
198    
199                        // Test for related, groupId / artifactId / version must match.
200                        if ( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
201                            reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() ) )
202                        {
203                            foundArtifacts.add( artifact );
204                        }
205                    }
206                    catch ( LayoutException e )
207                    {
208                        log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
209                    }
210                }
211            }
212    
213            return foundArtifacts;
214        }
215    
216        public String getRepoRoot()
217        {
218            return repository.getLocation();
219        }
220    
221        public ManagedRepository getRepository()
222        {
223            return repository;
224        }
225    
226        /**
227         * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
228         * information.
229         *
230         * @return the Set of available versions, based on the project reference.
231         * @throws org.apache.archiva.repository.layout.LayoutException
232         * @throws org.apache.archiva.repository.layout.LayoutException
233         */
234        public Set<String> getVersions( ProjectReference reference )
235            throws ContentNotFoundException, LayoutException
236        {
237            String path = toMetadataPath( reference );
238    
239            int idx = path.lastIndexOf( '/' );
240            if ( idx > 0 )
241            {
242                path = path.substring( 0, idx );
243            }
244    
245            File repoDir = new File( repository.getLocation(), path );
246    
247            if ( !repoDir.exists() )
248            {
249                throw new ContentNotFoundException(
250                    "Unable to get Versions on a non-existant directory: " + repoDir.getAbsolutePath() );
251            }
252    
253            if ( !repoDir.isDirectory() )
254            {
255                throw new ContentNotFoundException(
256                    "Unable to get Versions on a non-directory: " + repoDir.getAbsolutePath() );
257            }
258    
259            Set<String> foundVersions = new HashSet<String>();
260            VersionedReference versionRef = new VersionedReference();
261            versionRef.setGroupId( reference.getGroupId() );
262            versionRef.setArtifactId( reference.getArtifactId() );
263    
264            File repoFiles[] = repoDir.listFiles();
265            for ( int i = 0; i < repoFiles.length; i++ )
266            {
267                if ( !repoFiles[i].isDirectory() )
268                {
269                    // Skip it. not a directory.
270                    continue;
271                }
272    
273                // Test if dir has an artifact, which proves to us that it is a valid version directory.
274                String version = repoFiles[i].getName();
275                versionRef.setVersion( version );
276    
277                if ( hasArtifact( versionRef ) )
278                {
279                    // Found an artifact, must be a valid version.
280                    foundVersions.add( version );
281                }
282            }
283    
284            return foundVersions;
285        }
286    
287        public Set<String> getVersions( VersionedReference reference )
288            throws ContentNotFoundException
289        {
290            String path = toMetadataPath( reference );
291    
292            int idx = path.lastIndexOf( '/' );
293            if ( idx > 0 )
294            {
295                path = path.substring( 0, idx );
296            }
297    
298            File repoDir = new File( repository.getLocation(), path );
299    
300            if ( !repoDir.exists() )
301            {
302                throw new ContentNotFoundException(
303                    "Unable to get versions on a non-existant directory: " + repoDir.getAbsolutePath() );
304            }
305    
306            if ( !repoDir.isDirectory() )
307            {
308                throw new ContentNotFoundException(
309                    "Unable to get versions on a non-directory: " + repoDir.getAbsolutePath() );
310            }
311    
312            Set<String> foundVersions = new HashSet<String>();
313    
314            // First gather up the versions found as artifacts in the managed repository.
315            File repoFiles[] = repoDir.listFiles();
316            for ( int i = 0; i < repoFiles.length; i++ )
317            {
318                if ( repoFiles[i].isDirectory() )
319                {
320                    // Skip it. it's a directory.
321                    continue;
322                }
323    
324                String relativePath = PathUtil.getRelative( repository.getLocation(), repoFiles[i] );
325    
326                if ( filetypes.matchesDefaultExclusions( relativePath ) )
327                {
328                    // Skip it, it's metadata or similar
329                    continue;
330                }
331    
332                if ( filetypes.matchesArtifactPattern( relativePath ) )
333                {
334                    try
335                    {
336                        ArtifactReference artifact = toArtifactReference( relativePath );
337    
338                        foundVersions.add( artifact.getVersion() );
339                    }
340                    catch ( LayoutException e )
341                    {
342                        log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
343                    }
344                }
345            }
346    
347            return foundVersions;
348        }
349    
350        public boolean hasContent( ArtifactReference reference )
351        {
352            File artifactFile = toFile( reference );
353            return artifactFile.exists() && artifactFile.isFile();
354        }
355    
356        public boolean hasContent( ProjectReference reference )
357        {
358            try
359            {
360                Set<String> versions = getVersions( reference );
361                return !versions.isEmpty();
362            }
363            catch ( ContentNotFoundException e )
364            {
365                return false;
366            }
367            catch ( LayoutException e )
368            {
369                return false;
370            }
371        }
372    
373        public boolean hasContent( VersionedReference reference )
374        {
375            try
376            {
377                return ( getFirstArtifact( reference ) != null );
378            }
379            catch ( IOException e )
380            {
381                return false;
382            }
383            catch ( LayoutException e )
384            {
385                return false;
386            }
387        }
388    
389        public void setRepository( ManagedRepository repository )
390        {
391            this.repository = repository;
392        }
393    
394        /**
395         * Convert a path to an artifact reference.
396         *
397         * @param path the path to convert. (relative or full location path)
398         * @throws org.apache.archiva.repository.layout.LayoutException if the path cannot be converted to an artifact reference.
399         */
400        @Override
401        public ArtifactReference toArtifactReference( String path )
402            throws LayoutException
403        {
404            if ( ( path != null ) && path.startsWith( repository.getLocation() ) && repository.getLocation().length() > 0 )
405            {
406                return super.toArtifactReference( path.substring( repository.getLocation().length() + 1 ) );
407            }
408    
409            return super.toArtifactReference( path );
410        }
411    
412        public File toFile( ArtifactReference reference )
413        {
414            return new File( repository.getLocation(), toPath( reference ) );
415        }
416    
417        public File toFile( ArchivaArtifact reference )
418        {
419            return new File( repository.getLocation(), toPath( reference ) );
420        }
421    
422        /**
423         * Get the first Artifact found in the provided VersionedReference location.
424         *
425         * @param reference the reference to the versioned reference to search within
426         * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
427         *         no artifact was found within the versioned reference.
428         * @throws java.io.IOException     if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
429         * @throws org.apache.archiva.repository.layout.LayoutException
430         */
431        private ArtifactReference getFirstArtifact( VersionedReference reference )
432            throws LayoutException, IOException
433        {
434            String path = toMetadataPath( reference );
435    
436            int idx = path.lastIndexOf( '/' );
437            if ( idx > 0 )
438            {
439                path = path.substring( 0, idx );
440            }
441    
442            File repoDir = new File( repository.getLocation(), path );
443    
444            if ( !repoDir.exists() )
445            {
446                throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
447                                           + repoDir.getAbsolutePath() );
448            }
449    
450            if ( !repoDir.isDirectory() )
451            {
452                throw new IOException(
453                    "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.getAbsolutePath() );
454            }
455    
456            File repoFiles[] = repoDir.listFiles();
457            for ( int i = 0; i < repoFiles.length; i++ )
458            {
459                if ( repoFiles[i].isDirectory() )
460                {
461                    // Skip it. it's a directory.
462                    continue;
463                }
464    
465                String relativePath = PathUtil.getRelative( repository.getLocation(), repoFiles[i] );
466    
467                if ( filetypes.matchesArtifactPattern( relativePath ) )
468                {
469                    ArtifactReference artifact = toArtifactReference( relativePath );
470    
471                    return artifact;
472                }
473            }
474    
475            // No artifact was found.
476            return null;
477        }
478    
479        private boolean hasArtifact( VersionedReference reference )
480            throws LayoutException
481        {
482            try
483            {
484                return ( getFirstArtifact( reference ) != null );
485            }
486            catch ( IOException e )
487            {
488                return false;
489            }
490        }
491    
492        public void setFiletypes( FileTypes filetypes )
493        {
494            this.filetypes = filetypes;
495        }
496    }