View Javadoc
1   package org.apache.archiva.repository.content.maven2;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.archiva.admin.model.beans.ManagedRepository;
23  import org.apache.archiva.common.utils.PathUtil;
24  import org.apache.archiva.configuration.FileTypes;
25  import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
26  import org.apache.archiva.model.ArchivaArtifact;
27  import org.apache.archiva.model.ArtifactReference;
28  import org.apache.archiva.model.ProjectReference;
29  import org.apache.archiva.model.VersionedReference;
30  import org.apache.archiva.repository.ContentNotFoundException;
31  import org.apache.archiva.repository.ManagedRepositoryContent;
32  import org.apache.archiva.repository.RepositoryException;
33  import org.apache.archiva.repository.layout.LayoutException;
34  import org.apache.commons.io.FileUtils;
35  import org.apache.commons.lang.StringUtils;
36  import org.springframework.context.annotation.Scope;
37  import org.springframework.stereotype.Service;
38  
39  import javax.inject.Inject;
40  import javax.inject.Named;
41  import java.io.File;
42  import java.io.IOException;
43  import java.util.Collections;
44  import java.util.HashSet;
45  import java.util.Set;
46  
47  /**
48   * ManagedDefaultRepositoryContent
49   */
50  @Service ("managedRepositoryContent#default")
51  @Scope ("prototype")
52  public class ManagedDefaultRepositoryContent
53      extends AbstractDefaultRepositoryContent
54      implements ManagedRepositoryContent
55  {
56      @Inject
57      @Named ( "fileTypes" )
58      private FileTypes filetypes;
59  
60      private ManagedRepository repository;
61  
62      public ManagedDefaultRepositoryContent()
63      {
64          // default to use if there are none supplied as components
65          this.artifactMappingProviders = Collections.singletonList( new DefaultArtifactMappingProvider() );
66      }
67  
68      @Override
69      public void deleteVersion( VersionedReference reference )
70      {
71          String path = toMetadataPath( reference );
72          File projectPath = new File( getRepoRoot(), path );
73  
74          File projectDir = projectPath.getParentFile();
75          if ( projectDir.exists() && projectDir.isDirectory() )
76          {
77              FileUtils.deleteQuietly( projectDir );
78          }
79      }
80  
81      @Override
82      public void deleteProject( String namespace, String projectId )
83          throws RepositoryException, ContentNotFoundException
84      {
85          ArtifactReference artifactReference = new ArtifactReference();
86          artifactReference.setGroupId( namespace );
87          artifactReference.setArtifactId( projectId );
88          String path = toPath( artifactReference );
89          File directory = new File( getRepoRoot(), path );
90          if ( !directory.exists() )
91          {
92              throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
93          }
94          if ( directory.isDirectory() )
95          {
96              try
97              {
98                  FileUtils.deleteDirectory( directory );
99              }
100             catch ( IOException e )
101             {
102                 throw new RepositoryException( e.getMessage(), e );
103             }
104         }
105         else
106         {
107             log.warn( "project {}:{} is not a directory", namespace, projectId );
108         }
109 
110     }
111 
112     @Override
113     public void deleteArtifact( ArtifactReference artifactReference )
114     {
115         String path = toPath( artifactReference );
116         File filePath = new File( getRepoRoot(), path );
117 
118         if ( filePath.exists() )
119         {
120             FileUtils.deleteQuietly( filePath );
121         }
122 
123         File filePathmd5 = new File( getRepoRoot(), path + ".md5" );
124 
125         if ( filePathmd5.exists() )
126         {
127             FileUtils.deleteQuietly( filePathmd5 );
128         }
129 
130         File filePathsha1 = new File( getRepoRoot(), path + ".sha1" );
131 
132         if ( filePathsha1.exists() )
133         {
134             FileUtils.deleteQuietly( filePathsha1 );
135         }
136     }
137 
138     @Override
139     public void deleteGroupId( String groupId )
140         throws ContentNotFoundException
141     {
142 
143         String path = StringUtils.replaceChars( groupId, '.', '/' );
144 
145         File directory = new File( getRepoRoot(), path );
146 
147         if ( directory.exists() )
148         {
149             try
150             {
151                 FileUtils.deleteDirectory( directory );
152             }
153             catch ( IOException e )
154             {
155                 log.warn( "skip error deleting directory {}:", directory.getPath(), e );
156             }
157         }
158     }
159 
160     @Override
161     public String getId()
162     {
163         return repository.getId();
164     }
165 
166     @Override
167     public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
168         throws ContentNotFoundException
169     {
170         File artifactFile = toFile( reference );
171         File repoDir = artifactFile.getParentFile();
172 
173         if ( !repoDir.exists() )
174         {
175             throw new ContentNotFoundException(
176                 "Unable to get related artifacts using a non-existant directory: " + repoDir.getAbsolutePath() );
177         }
178 
179         if ( !repoDir.isDirectory() )
180         {
181             throw new ContentNotFoundException(
182                 "Unable to get related artifacts using a non-directory: " + repoDir.getAbsolutePath() );
183         }
184 
185         Set<ArtifactReference> foundArtifacts = new HashSet<>();
186 
187         // First gather up the versions found as artifacts in the managed repository.
188         File repoFiles[] = repoDir.listFiles();
189         for (File repoFile : repoFiles) 
190         {
191             if (repoFile.isDirectory()) {
192                 // Skip it. it's a directory.
193                 continue;
194             }
195             String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile);
196             if ( filetypes.matchesArtifactPattern( relativePath ) )
197             {
198                 try
199                 {
200                     ArtifactReference artifact = toArtifactReference( relativePath );
201 
202                     // Test for related, groupId / artifactId / version must match.
203                     if ( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
204                             reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() ) )
205                     {
206                         foundArtifacts.add( artifact );
207                     }
208                 }
209                 catch ( LayoutException e )
210                 {
211                     log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
212                 }
213             }
214         }
215 
216         return foundArtifacts;
217     }
218 
219     @Override
220     public String getRepoRoot()
221     {
222         return repository.getLocation();
223     }
224 
225     @Override
226     public ManagedRepository getRepository()
227     {
228         return repository;
229     }
230 
231     /**
232      * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
233      * information.
234      *
235      * @return the Set of available versions, based on the project reference.
236      * @throws org.apache.archiva.repository.layout.LayoutException
237      * @throws org.apache.archiva.repository.layout.LayoutException
238      */
239     @Override
240     public Set<String> getVersions( ProjectReference reference )
241         throws ContentNotFoundException, LayoutException
242     {
243         String path = toMetadataPath( reference );
244 
245         int idx = path.lastIndexOf( '/' );
246         if ( idx > 0 )
247         {
248             path = path.substring( 0, idx );
249         }
250 
251         File repoDir = new File( repository.getLocation(), path );
252 
253         if ( !repoDir.exists() )
254         {
255             throw new ContentNotFoundException(
256                 "Unable to get Versions on a non-existant directory: " + repoDir.getAbsolutePath() );
257         }
258 
259         if ( !repoDir.isDirectory() )
260         {
261             throw new ContentNotFoundException(
262                 "Unable to get Versions on a non-directory: " + repoDir.getAbsolutePath() );
263         }
264 
265         Set<String> foundVersions = new HashSet<>();
266         VersionedReference versionRef = new VersionedReference();
267         versionRef.setGroupId( reference.getGroupId() );
268         versionRef.setArtifactId( reference.getArtifactId() );
269 
270         File repoFiles[] = repoDir.listFiles();
271         for (File repoFile : repoFiles) 
272         {
273             if (!repoFile.isDirectory()) {
274                 // Skip it. not a directory.
275                 continue;
276             }
277             // Test if dir has an artifact, which proves to us that it is a valid version directory.
278             String version = repoFile.getName();
279             versionRef.setVersion( version );
280             if ( hasArtifact( versionRef ) )
281             {
282                 // Found an artifact, must be a valid version.
283                 foundVersions.add( version );
284             }
285         }
286 
287         return foundVersions;
288     }
289 
290     @Override
291     public Set<String> getVersions( VersionedReference reference )
292         throws ContentNotFoundException
293     {
294         String path = toMetadataPath( reference );
295 
296         int idx = path.lastIndexOf( '/' );
297         if ( idx > 0 )
298         {
299             path = path.substring( 0, idx );
300         }
301 
302         File repoDir = new File( repository.getLocation(), path );
303 
304         if ( !repoDir.exists() )
305         {
306             throw new ContentNotFoundException(
307                 "Unable to get versions on a non-existant directory: " + repoDir.getAbsolutePath() );
308         }
309 
310         if ( !repoDir.isDirectory() )
311         {
312             throw new ContentNotFoundException(
313                 "Unable to get versions on a non-directory: " + repoDir.getAbsolutePath() );
314         }
315 
316         Set<String> foundVersions = new HashSet<>();
317 
318         // First gather up the versions found as artifacts in the managed repository.
319         File repoFiles[] = repoDir.listFiles();
320         for (File repoFile : repoFiles) 
321         {
322             if (repoFile.isDirectory()) {
323                 // Skip it. it's a directory.
324                 continue;
325             }
326             String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile);
327             if ( filetypes.matchesDefaultExclusions( relativePath ) )
328             {
329                 // Skip it, it's metadata or similar
330                 continue;
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     @Override
351     public boolean hasContent( ArtifactReference reference )
352     {
353         File artifactFile = toFile( reference );
354         return artifactFile.exists() && artifactFile.isFile();
355     }
356 
357     @Override
358     public boolean hasContent( ProjectReference reference )
359     {
360         try
361         {
362             Set<String> versions = getVersions( reference );
363             return !versions.isEmpty();
364         }
365         catch ( ContentNotFoundException | LayoutException e )
366         {
367             return false;
368         }
369     }
370 
371     @Override
372     public boolean hasContent( VersionedReference reference )
373     {
374         try
375         {
376             return ( getFirstArtifact( reference ) != null );
377         }
378         catch ( IOException | LayoutException e )
379         {
380             return false;
381         }
382     }
383 
384     @Override
385     public void setRepository( ManagedRepository repository )
386     {
387         this.repository = repository;
388     }
389 
390     /**
391      * Convert a path to an artifact reference.
392      *
393      * @param path the path to convert. (relative or full location path)
394      * @throws org.apache.archiva.repository.layout.LayoutException if the path cannot be converted to an artifact reference.
395      */
396     @Override
397     public ArtifactReference toArtifactReference( String path )
398         throws LayoutException
399     {
400         if ( ( path != null ) && path.startsWith( repository.getLocation() ) && repository.getLocation().length() > 0 )
401         {
402             return super.toArtifactReference( path.substring( repository.getLocation().length() + 1 ) );
403         }
404 
405         return super.toArtifactReference( path );
406     }
407 
408     @Override
409     public File toFile( ArtifactReference reference )
410     {
411         return new File( repository.getLocation(), toPath( reference ) );
412     }
413 
414     @Override
415     public File toFile( ArchivaArtifact reference )
416     {
417         return new File( repository.getLocation(), toPath( reference ) );
418     }
419 
420     /**
421      * Get the first Artifact found in the provided VersionedReference location.
422      *
423      * @param reference the reference to the versioned reference to search within
424      * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
425      *         no artifact was found within the versioned reference.
426      * @throws java.io.IOException     if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
427      * @throws org.apache.archiva.repository.layout.LayoutException
428      */
429     private ArtifactReference getFirstArtifact( VersionedReference reference )
430         throws LayoutException, IOException
431     {
432         String path = toMetadataPath( reference );
433 
434         int idx = path.lastIndexOf( '/' );
435         if ( idx > 0 )
436         {
437             path = path.substring( 0, idx );
438         }
439 
440         File repoDir = new File( repository.getLocation(), path );
441 
442         if ( !repoDir.exists() )
443         {
444             throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
445                                        + repoDir.getAbsolutePath() );
446         }
447 
448         if ( !repoDir.isDirectory() )
449         {
450             throw new IOException(
451                 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.getAbsolutePath() );
452         }
453 
454         File repoFiles[] = repoDir.listFiles();
455         for (File repoFile : repoFiles) 
456         {
457             if (repoFile.isDirectory()) {
458                 // Skip it. it's a directory.
459                 continue;
460             }
461             String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile);
462             if ( filetypes.matchesArtifactPattern( relativePath ) )
463             {
464                 ArtifactReference artifact = toArtifactReference( relativePath );
465 
466                 return artifact;
467             }
468         }
469 
470         // No artifact was found.
471         return null;
472     }
473 
474     private boolean hasArtifact( VersionedReference reference )
475         throws LayoutException
476     {
477         try
478         {
479             return ( getFirstArtifact( reference ) != null );
480         }
481         catch ( IOException e )
482         {
483             return false;
484         }
485     }
486 
487     public void setFiletypes( FileTypes filetypes )
488     {
489         this.filetypes = filetypes;
490     }
491 }