]> source.dussan.org Git - archiva.git/blob
970645139b604b59c627ca0b8ac62cb5dec56169
[archiva.git] /
1 package org.apache.archiva.repository.mock;
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.common.filelock.DefaultFileLockManager;
23 import org.apache.archiva.common.utils.VersionUtil;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.maven.model.MavenArtifactFacet;
26 import org.apache.archiva.model.ArtifactReference;
27 import org.apache.archiva.model.ProjectReference;
28 import org.apache.archiva.model.VersionedReference;
29 import org.apache.archiva.repository.*;
30 import org.apache.archiva.repository.content.Artifact;
31 import org.apache.archiva.repository.content.BaseDataItemTypes;
32 import org.apache.archiva.repository.content.ContentItem;
33 import org.apache.archiva.repository.content.DataItem;
34 import org.apache.archiva.repository.content.ItemNotFoundException;
35 import org.apache.archiva.repository.content.ItemSelector;
36 import org.apache.archiva.repository.content.Namespace;
37 import org.apache.archiva.repository.content.Project;
38 import org.apache.archiva.repository.content.Version;
39 import org.apache.archiva.repository.content.base.ArchivaArtifact;
40 import org.apache.archiva.repository.content.base.ArchivaContentItem;
41 import org.apache.archiva.repository.content.base.ArchivaDataItem;
42 import org.apache.archiva.repository.content.base.ArchivaNamespace;
43 import org.apache.archiva.repository.content.base.ArchivaProject;
44 import org.apache.archiva.repository.content.base.ArchivaVersion;
45 import org.apache.archiva.repository.storage.fs.FilesystemStorage;
46 import org.apache.archiva.repository.storage.RepositoryStorage;
47 import org.apache.archiva.repository.storage.StorageAsset;
48 import org.apache.commons.lang3.StringUtils;
49 import org.springframework.stereotype.Service;
50
51 import java.io.IOException;
52 import java.nio.file.Path;
53 import java.nio.file.Paths;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.function.Consumer;
58 import java.util.regex.Matcher;
59 import java.util.regex.Pattern;
60 import java.util.stream.Stream;
61
62 /**
63  * @author Martin Stockhammer <martin_s@apache.org>
64  */
65 @Service("managedRepositoryContent#mock")
66 public class ManagedRepositoryContentMock implements BaseRepositoryContentLayout, ManagedRepositoryContent
67 {
68     private static final String PATH_SEPARATOR = "/";
69     private static final String GROUP_SEPARATOR = ".";
70     public static final String MAVEN_METADATA = "maven-metadata.xml";
71
72
73     private ManagedRepository repository;
74     private RepositoryStorage fsStorage;
75
76     ManagedRepositoryContentMock(ManagedRepository repo) {
77         this.repository = repo;
78         this.fsStorage = repo;
79     }
80
81     @Override
82     public VersionedReference toVersion( String groupId, String artifactId, String version )
83     {
84         return null;
85     }
86
87     @Override
88     public VersionedReference toVersion( ArtifactReference artifactReference )
89     {
90         return null;
91     }
92
93     @Override
94     public <T extends ContentItem> T adaptItem( Class<T> clazz, ContentItem item ) throws LayoutException
95     {
96         if (clazz.isAssignableFrom( Version.class ))
97         {
98             if ( !item.hasCharacteristic( Version.class ) )
99             {
100                 item.setCharacteristic( Version.class, createVersionFromPath( item.getAsset() ) );
101             }
102             return (T) item.adapt( Version.class );
103         } else if ( clazz.isAssignableFrom( Project.class )) {
104             if ( !item.hasCharacteristic( Project.class ) )
105             {
106                 item.setCharacteristic( Project.class, createProjectFromPath( item.getAsset() ) );
107             }
108             return (T) item.adapt( Project.class );
109         } else if ( clazz.isAssignableFrom( Namespace.class )) {
110             if ( !item.hasCharacteristic( Namespace.class ) )
111             {
112                 item.setCharacteristic( Namespace.class, createNamespaceFromPath( item.getAsset() ) );
113             }
114             return (T) item.adapt( Namespace.class );
115         }
116         throw new LayoutException( "Could not convert item to class " + clazz);
117     }
118
119     private Version createVersionFromPath( StorageAsset asset )
120     {
121         Project proj = createProjectFromPath( asset.getParent( ) );
122         return ArchivaVersion.withRepository( this ).withAsset( asset )
123             .withProject( proj ).withVersion( asset.getName( ) ).build();
124     }
125
126     private Project createProjectFromPath( StorageAsset asset)  {
127         Namespace ns = createNamespaceFromPath( asset );
128         return ArchivaProject.withRepository( this ).withAsset( asset )
129             .withNamespace( ns ).withId( asset.getName( ) ).build( );
130     }
131
132     private Namespace createNamespaceFromPath( StorageAsset asset) {
133         String namespace = asset.getPath( ).replace( "/", "." );
134         return ArchivaNamespace.withRepository( this )
135             .withAsset( asset ).withNamespace( namespace ).build();
136     }
137
138     @Override
139     public void deleteAllItems( ItemSelector selector, Consumer<ItemDeleteStatus> consumer ) throws ContentAccessException, IllegalArgumentException
140     {
141
142     }
143
144     @Override
145     public void deleteItem( ContentItem item ) throws ItemNotFoundException, ContentAccessException
146     {
147
148     }
149
150     @Override
151     public ContentItem getItem( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
152     {
153         return null;
154     }
155
156     @Override
157     public Namespace getNamespace( ItemSelector namespaceSelector ) throws ContentAccessException, IllegalArgumentException
158     {
159         return null;
160     }
161
162     @Override
163     public Project getProject( ItemSelector projectSelector ) throws ContentAccessException, IllegalArgumentException
164     {
165         return null;
166     }
167
168     @Override
169     public Version getVersion( ItemSelector versionCoordinates ) throws ContentAccessException, IllegalArgumentException
170     {
171         return null;
172     }
173
174     @Override
175     public Artifact getArtifact( ItemSelector selector ) throws ContentAccessException
176     {
177         StringBuilder path = new StringBuilder(selector.getNamespace( ).replace( ".", "/" ));
178         path.append( "/" ).append( selector.getProjectId( ) ).append( "/" ).append( selector.getVersion( ) );
179         path.append( "/" ).append( selector.getArtifactId( ) ).append( "-" ).append( selector.getArtifactVersion( ) ).append( "." ).append( selector.getType( ) );
180         StorageAsset asset = fsStorage.getAsset( path.toString( ) );
181         ArchivaNamespace ns = ArchivaNamespace.withRepository( repository.getContent( ) ).withAsset( asset.getParent( ).getParent( ).getParent( ) ).withNamespace( selector.getNamespace( ) ).build( );
182         ArchivaProject project = ArchivaProject.withRepository( repository.getContent( ) ).withAsset( asset.getParent( ).getParent( ) ).withNamespace( ns ).withId( selector.getProjectId( ) ).build( );
183         ArchivaVersion version = ArchivaVersion.withRepository( repository.getContent( ) ).withAsset( asset.getParent( ) ).withProject( project ).withVersion( selector.getVersion( ) ).build( );
184         ArchivaArtifact artifact = ArchivaArtifact.withAsset( asset ).withVersion( version ).withId( selector.getArtifactId( ) ).withArtifactVersion( selector.getArtifactVersion( ) ).withType( selector.getType( ) ).build( );
185         return artifact;
186     }
187
188     @Override
189     public List<? extends Artifact> getArtifacts( ItemSelector selector ) throws ContentAccessException
190     {
191         return null;
192     }
193
194     @Override
195     public Stream<? extends Artifact> newArtifactStream( ItemSelector selector ) throws ContentAccessException
196     {
197         return null;
198     }
199
200     @Override
201     public Stream<? extends ContentItem> newItemStream( ItemSelector selector, boolean parallel ) throws ContentAccessException, IllegalArgumentException
202     {
203         return null;
204     }
205
206     @Override
207     public List<? extends Project> getProjects( Namespace namespace ) throws ContentAccessException
208     {
209         return null;
210     }
211
212     @Override
213     public List<? extends Project> getProjects( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
214     {
215         return null;
216     }
217
218     @Override
219     public List<? extends Version> getVersions( Project project ) throws ContentAccessException
220     {
221         return null;
222     }
223
224     @Override
225     public List<? extends Version> getVersions( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
226     {
227         return null;
228     }
229
230     @Override
231     public List<String> getArtifactVersions( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
232     {
233         return null;
234     }
235
236     @Override
237     public List<? extends Artifact> getArtifacts( ContentItem item ) throws ContentAccessException
238     {
239         return null;
240     }
241
242     @Override
243     public Stream<? extends Artifact> newArtifactStream( ContentItem item ) throws ContentAccessException
244     {
245         return null;
246     }
247
248     @Override
249     public boolean hasContent( ItemSelector selector )
250     {
251         return false;
252     }
253
254     @Override
255     public ContentItem getParent( ContentItem item )
256     {
257         try
258         {
259             return toItem( item.getAsset( ).getParent( ) );
260         }
261         catch ( LayoutException e )
262         {
263             throw new RuntimeException( "Bad layout conversion " + e.getMessage( ) );
264         }
265     }
266
267     @Override
268     public List<? extends ContentItem> getChildren( ContentItem item )
269     {
270         return null;
271     }
272
273     @Override
274     public <T extends ContentItem> T applyCharacteristic( Class<T> clazz, ContentItem item ) throws LayoutException
275     {
276         return null;
277     }
278
279     @Override
280     public <T extends ManagedRepositoryContentLayout> T getLayout( Class<T> clazz ) throws LayoutException
281     {
282         return (T) this;
283     }
284
285     @Override
286     public <T extends ManagedRepositoryContentLayout> boolean supportsLayout( Class<T> clazz )
287     {
288         return true;
289     }
290
291     @Override
292     public void addArtifact( Path sourceFile, Artifact destination ) throws IllegalArgumentException
293     {
294
295     }
296
297     @Override
298     public DataItem getMetadataItem( Version version )
299     {
300         return ArchivaDataItem.withAsset( version.getAsset( ).resolve( "maven-metadata.xml" ) ).withId( "maven-metadata.xml" )
301             .withDataType( BaseDataItemTypes.METADATA ).build();
302     }
303
304     @Override
305     public DataItem getMetadataItem( Project project )
306     {
307         return ArchivaDataItem.withAsset( project.getAsset( ).resolve( "maven-metadata.xml" ) ).withId( "maven-metadata.xml" )
308             .withDataType( BaseDataItemTypes.METADATA ).build( );
309     }
310
311     @Override
312     public ContentItem toItem( String path ) throws LayoutException
313     {
314         StorageAsset asset = repository.getAsset( "" ).resolve( path );
315         return toItem( asset );
316     }
317
318     @Override
319     public ContentItem toItem( StorageAsset asset ) throws LayoutException
320     {
321         if (asset.isLeaf()) {
322             return ArchivaDataItem.withAsset( asset ).withId( asset.getName( ) ).build();
323         } else
324         {
325             return ArchivaContentItem.withRepository( this )
326                 .withAsset( asset )
327                 .build( );
328         }
329     }
330
331     @Override
332     public void deleteVersion( VersionedReference reference ) throws ContentNotFoundException, ContentAccessException
333     {
334
335     }
336
337     @Override
338     public void deleteArtifact( ArtifactReference artifactReference ) throws ContentNotFoundException, ContentAccessException
339     {
340
341     }
342
343     @Override
344     public void deleteGroupId( String groupId ) throws ContentNotFoundException, ContentAccessException
345     {
346
347     }
348
349     @Override
350     public void deleteProject( String namespace, String projectId ) throws ContentNotFoundException, ContentAccessException
351     {
352
353     }
354
355     @Override
356     public void deleteProject( ProjectReference reference ) throws ContentNotFoundException, ContentAccessException
357     {
358
359     }
360
361     @Override
362     public String toPath( ContentItem item )
363     {
364         return item.getAsset( ).getPath( );
365     }
366
367     @Override
368     public String getId( )
369     {
370         return repository.getId();
371     }
372
373     @Override
374     public List<ArtifactReference> getRelatedArtifacts( VersionedReference reference ) throws ContentNotFoundException, LayoutException, ContentAccessException
375     {
376         return null;
377     }
378
379     @Override
380     public List<ArtifactReference> getArtifacts( VersionedReference reference ) throws ContentNotFoundException, LayoutException, ContentAccessException
381     {
382         return null;
383     }
384
385     @Override
386     public String getRepoRoot( )
387     {
388         return getRepoRootAsset().getFilePath().toString();
389     }
390
391     private StorageAsset getRepoRootAsset() {
392         if (fsStorage==null) {
393             try {
394                 fsStorage = new FilesystemStorage(Paths.get("", "target", "test-repository", "managed"), new DefaultFileLockManager());
395             } catch (IOException e) {
396                 e.printStackTrace();
397             }
398         }
399         return fsStorage.getAsset("");
400     }
401
402     @Override
403     public ManagedRepository getRepository( )
404     {
405         return repository;
406     }
407
408     @Override
409     public void setRepository( ManagedRepository repo )
410     {
411         this.repository = repo;
412     }
413
414     @Override
415     public StorageAsset toFile( VersionedReference reference )
416     {
417         return null;
418     }
419
420     private Map<ArtifactReference, String> refs = new HashMap<>();
421
422     @Override
423     public ArtifactReference toArtifactReference( String path ) throws LayoutException
424     {
425         if ( StringUtils.isBlank( path ) )
426         {
427             throw new LayoutException( "Unable to convert blank path." );
428         }
429
430         ArtifactMetadata metadata = getArtifactForPath("test-repository", path);
431
432         ArtifactReference artifact = new ArtifactReference();
433         artifact.setGroupId( metadata.getNamespace() );
434         artifact.setArtifactId( metadata.getProject() );
435         artifact.setVersion( metadata.getVersion() );
436         artifact.setProjectVersion( metadata.getProjectVersion( ) );
437         MavenArtifactFacet facet = (MavenArtifactFacet) metadata.getFacet( MavenArtifactFacet.FACET_ID );
438         if ( facet != null )
439         {
440             artifact.setClassifier( facet.getClassifier() );
441             artifact.setType( facet.getType() );
442         }
443         refs.put(artifact, path);
444         return artifact;
445     }
446
447     public ArtifactMetadata getArtifactForPath( String repoId, String relativePath )
448     {
449         String[] parts = relativePath.replace( '\\', '/' ).split( "/" );
450
451         int len = parts.length;
452         if ( len < 4 )
453         {
454             throw new IllegalArgumentException(
455                     "Not a valid artifact path in a Maven 2 repository, not enough directories: " + relativePath );
456         }
457
458         String id = parts[--len];
459         String baseVersion = parts[--len];
460         String artifactId = parts[--len];
461         StringBuilder groupIdBuilder = new StringBuilder();
462         for ( int i = 0; i < len - 1; i++ )
463         {
464             groupIdBuilder.append( parts[i] );
465             groupIdBuilder.append( '.' );
466         }
467         groupIdBuilder.append( parts[len - 1] );
468
469         return getArtifactFromId( repoId, groupIdBuilder.toString(), artifactId, baseVersion, id );
470     }
471
472     private static final Pattern TIMESTAMP_PATTERN = Pattern.compile( "([0-9]{8}.[0-9]{6})-([0-9]+).*" );
473
474
475
476     public ArtifactMetadata getArtifactFromId( String repoId, String namespace, String projectId, String projectVersion,
477                                                String id )
478     {
479         if ( !id.startsWith( projectId + "-" ) )
480         {
481             throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
482                     + "' doesn't start with artifact ID '" + projectId + "'" );
483         }
484
485         MavenArtifactFacet facet = new MavenArtifactFacet();
486
487         int index = projectId.length() + 1;
488         String version;
489         String idSubStrFromVersion = id.substring( index );
490         if ( idSubStrFromVersion.startsWith( projectVersion ) && !VersionUtil.isUniqueSnapshot( projectVersion ) )
491         {
492             // non-snapshot versions, or non-timestamped snapshot versions
493             version = projectVersion;
494         }
495         else if ( VersionUtil.isGenericSnapshot( projectVersion ) )
496         {
497             // timestamped snapshots
498             try
499             {
500                 int mainVersionLength = projectVersion.length() - 8; // 8 is length of "SNAPSHOT"
501                 if ( mainVersionLength == 0 )
502                 {
503                     throw new IllegalArgumentException(
504                             "Timestamped snapshots must contain the main version, filename was '" + id + "'" );
505                 }
506
507                 Matcher m = TIMESTAMP_PATTERN.matcher( idSubStrFromVersion.substring( mainVersionLength ) );
508                 m.matches();
509                 String timestamp = m.group( 1 );
510                 String buildNumber = m.group( 2 );
511                 facet.setTimestamp( timestamp );
512                 facet.setBuildNumber( Integer.parseInt( buildNumber ) );
513                 version = idSubStrFromVersion.substring( 0, mainVersionLength ) + timestamp + "-" + buildNumber;
514             }
515             catch ( IllegalStateException e )
516             {
517                 throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
518                         + "' doesn't contain a timestamped version matching snapshot '"
519                         + projectVersion + "'", e);
520             }
521         }
522         else
523         {
524             // invalid
525             throw new IllegalArgumentException(
526                     "Not a valid artifact path in a Maven 2 repository, filename '" + id + "' doesn't contain version '"
527                             + projectVersion + "'" );
528         }
529
530         String classifier;
531         String ext;
532         index += version.length();
533         if ( index == id.length() )
534         {
535             // no classifier or extension
536             classifier = null;
537             ext = null;
538         }
539         else
540         {
541             char c = id.charAt( index );
542             if ( c == '-' )
543             {
544                 // classifier up until '.'
545                 int extIndex = id.indexOf( '.', index );
546                 if ( extIndex >= 0 )
547                 {
548                     classifier = id.substring( index + 1, extIndex );
549                     ext = id.substring( extIndex + 1 );
550                 }
551                 else
552                 {
553                     classifier = id.substring( index + 1 );
554                     ext = null;
555                 }
556             }
557             else if ( c == '.' )
558             {
559                 // rest is the extension
560                 classifier = null;
561                 ext = id.substring( index + 1 );
562             }
563             else
564             {
565                 throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
566                         + "' expected classifier or extension but got '"
567                         + id.substring( index ) + "'" );
568             }
569         }
570
571         ArtifactMetadata metadata = new ArtifactMetadata();
572         metadata.setId( id );
573         metadata.setNamespace( namespace );
574         metadata.setProject( projectId );
575         metadata.setRepositoryId( repoId );
576         metadata.setProjectVersion( projectVersion );
577         metadata.setVersion( version );
578
579         facet.setClassifier( classifier );
580
581         // we use our own provider here instead of directly accessing Maven's artifact handlers as it has no way
582         // to select the correct order to apply multiple extensions mappings to a preferred type
583         // TODO: this won't allow the user to decide order to apply them if there are conflicts or desired changes -
584         //       perhaps the plugins could register missing entries in configuration, then we just use configuration
585         //       here?
586
587         String type = null;
588
589
590         // use extension as default
591         if ( type == null )
592         {
593             type = ext;
594         }
595
596         // TODO: should we allow this instead?
597         if ( type == null )
598         {
599             throw new IllegalArgumentException(
600                     "Not a valid artifact path in a Maven 2 repository, filename '" + id + "' does not have a type" );
601         }
602
603         facet.setType( type );
604         metadata.addFacet( facet );
605
606         return metadata;
607     }
608
609
610     @Override
611     public StorageAsset toFile( ArtifactReference reference )
612     {
613         return getRepoRootAsset().resolve( refs.get(reference));
614     }
615
616     private String formatAsDirectory( String directory )
617     {
618         return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
619     }
620
621     @Override
622     public String toPath( ArtifactReference reference )
623     {
624         return null;
625     }
626
627     @Override
628     public String toPath( ItemSelector selector )
629     {
630         return null;
631     }
632
633     @Override
634     public ItemSelector toItemSelector( String path ) throws LayoutException
635     {
636         return null;
637     }
638
639     @Override
640     public ManagedRepositoryContent getGenericContent( )
641     {
642         return null;
643     }
644 }