This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.metadata.repository.file;
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.configuration.ArchivaConfiguration;
023import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
024import org.apache.archiva.metadata.model.ArtifactMetadata;
025import org.apache.archiva.metadata.model.CiManagement;
026import org.apache.archiva.metadata.model.Dependency;
027import org.apache.archiva.metadata.model.IssueManagement;
028import org.apache.archiva.metadata.model.License;
029import org.apache.archiva.metadata.model.MailingList;
030import org.apache.archiva.metadata.model.MetadataFacet;
031import org.apache.archiva.metadata.model.MetadataFacetFactory;
032import org.apache.archiva.metadata.model.Organization;
033import org.apache.archiva.metadata.model.ProjectMetadata;
034import org.apache.archiva.metadata.model.ProjectVersionMetadata;
035import org.apache.archiva.metadata.model.ProjectVersionReference;
036import org.apache.archiva.metadata.model.Scm;
037import org.apache.archiva.metadata.repository.MetadataRepository;
038import org.apache.archiva.metadata.repository.MetadataRepositoryException;
039import org.apache.archiva.metadata.repository.MetadataResolutionException;
040import org.apache.commons.io.FileUtils;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044import java.io.File;
045import java.io.FileNotFoundException;
046import java.io.IOException;
047import java.io.InputStream;
048import java.io.OutputStream;
049import java.nio.file.Files;
050import java.nio.file.NoSuchFileException;
051import java.util.ArrayList;
052import java.util.Arrays;
053import java.util.Collection;
054import java.util.Collections;
055import java.util.Comparator;
056import java.util.Date;
057import java.util.HashMap;
058import java.util.HashSet;
059import java.util.LinkedHashSet;
060import java.util.List;
061import java.util.Map;
062import java.util.Properties;
063import java.util.Set;
064import java.util.StringTokenizer;
065
066public class FileMetadataRepository
067    implements MetadataRepository
068{
069    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
070
071    private final ArchivaConfiguration configuration;
072
073    private Logger log = LoggerFactory.getLogger( FileMetadataRepository.class );
074
075    private static final String PROJECT_METADATA_KEY = "project-metadata";
076
077    private static final String PROJECT_VERSION_METADATA_KEY = "version-metadata";
078
079    private static final String NAMESPACE_METADATA_KEY = "namespace-metadata";
080
081    private static final String METADATA_KEY = "metadata";
082
083    public FileMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
084                                   ArchivaConfiguration configuration )
085    {
086        this.metadataFacetFactories = metadataFacetFactories;
087        this.configuration = configuration;
088    }
089
090    private File getBaseDirectory( String repoId )
091        throws IOException
092    {
093        // TODO: should be configurable, like the index
094        ManagedRepositoryConfiguration managedRepositoryConfiguration =
095            configuration.getConfiguration().getManagedRepositoriesAsMap().get( repoId );
096        if ( managedRepositoryConfiguration == null )
097        {
098            return Files.createTempDirectory( repoId ).toFile();
099        }
100        String basedir = managedRepositoryConfiguration.getLocation();
101        return new File( basedir, ".archiva" );
102    }
103
104    private File getDirectory( String repoId )
105        throws IOException
106    {
107        return new File( getBaseDirectory( repoId ), "content" );
108    }
109
110    @Override
111    public void updateProject( String repoId, ProjectMetadata project )
112    {
113        updateProject( repoId, project.getNamespace(), project.getId() );
114    }
115
116    private void updateProject( String repoId, String namespace, String id )
117    {
118        // TODO: this is a more braindead implementation than we would normally expect, for prototyping purposes
119        updateNamespace( repoId, namespace );
120
121        try
122        {
123            File namespaceDirectory = new File( getDirectory( repoId ), namespace );
124            Properties properties = new Properties();
125            properties.setProperty( "namespace", namespace );
126            properties.setProperty( "id", id );
127            writeProperties( properties, new File( namespaceDirectory, id ), PROJECT_METADATA_KEY );
128        }
129        catch ( IOException e )
130        {
131            // TODO!
132            log.error( e.getMessage(), e );
133        }
134    }
135
136    @Override
137    public void updateProjectVersion( String repoId, String namespace, String projectId,
138                                      ProjectVersionMetadata versionMetadata )
139    {
140
141        try
142        {
143            updateProject( repoId, namespace, projectId );
144
145            File directory =
146                new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + versionMetadata.getId() );
147
148            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
149            // remove properties that are not references or artifacts
150            for ( Object key : new ArrayList( properties.keySet() ) )
151            {
152                String name = (String) key;
153                if ( !name.contains( ":" ) && !name.equals( "facetIds" ) )
154                {
155                    properties.remove( name );
156                }
157
158                // clear the facet contents so old properties are no longer written
159                clearMetadataFacetProperties( versionMetadata.getFacetList(), properties, "" );
160            }
161            properties.setProperty( "id", versionMetadata.getId() );
162            setProperty( properties, "name", versionMetadata.getName() );
163            setProperty( properties, "description", versionMetadata.getDescription() );
164            setProperty( properties, "url", versionMetadata.getUrl() );
165            setProperty( properties, "incomplete", String.valueOf( versionMetadata.isIncomplete() ) );
166            if ( versionMetadata.getScm() != null )
167            {
168                setProperty( properties, "scm.connection", versionMetadata.getScm().getConnection() );
169                setProperty( properties, "scm.developerConnection", versionMetadata.getScm().getDeveloperConnection() );
170                setProperty( properties, "scm.url", versionMetadata.getScm().getUrl() );
171            }
172            if ( versionMetadata.getCiManagement() != null )
173            {
174                setProperty( properties, "ci.system", versionMetadata.getCiManagement().getSystem() );
175                setProperty( properties, "ci.url", versionMetadata.getCiManagement().getUrl() );
176            }
177            if ( versionMetadata.getIssueManagement() != null )
178            {
179                setProperty( properties, "issue.system", versionMetadata.getIssueManagement().getSystem() );
180                setProperty( properties, "issue.url", versionMetadata.getIssueManagement().getUrl() );
181            }
182            if ( versionMetadata.getOrganization() != null )
183            {
184                setProperty( properties, "org.name", versionMetadata.getOrganization().getName() );
185                setProperty( properties, "org.url", versionMetadata.getOrganization().getUrl() );
186            }
187            int i = 0;
188            for ( License license : versionMetadata.getLicenses() )
189            {
190                setProperty( properties, "license." + i + ".name", license.getName() );
191                setProperty( properties, "license." + i + ".url", license.getUrl() );
192                i++;
193            }
194            i = 0;
195            for ( MailingList mailingList : versionMetadata.getMailingLists() )
196            {
197                setProperty( properties, "mailingList." + i + ".archive", mailingList.getMainArchiveUrl() );
198                setProperty( properties, "mailingList." + i + ".name", mailingList.getName() );
199                setProperty( properties, "mailingList." + i + ".post", mailingList.getPostAddress() );
200                setProperty( properties, "mailingList." + i + ".unsubscribe", mailingList.getUnsubscribeAddress() );
201                setProperty( properties, "mailingList." + i + ".subscribe", mailingList.getSubscribeAddress() );
202                setProperty( properties, "mailingList." + i + ".otherArchives",
203                             join( mailingList.getOtherArchives() ) );
204                i++;
205            }
206            i = 0;
207            ProjectVersionReference reference = new ProjectVersionReference();
208            reference.setNamespace( namespace );
209            reference.setProjectId( projectId );
210            reference.setProjectVersion( versionMetadata.getId() );
211            reference.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
212            for ( Dependency dependency : versionMetadata.getDependencies() )
213            {
214                setProperty( properties, "dependency." + i + ".classifier", dependency.getClassifier() );
215                setProperty( properties, "dependency." + i + ".scope", dependency.getScope() );
216                setProperty( properties, "dependency." + i + ".systemPath", dependency.getSystemPath() );
217                setProperty( properties, "dependency." + i + ".artifactId", dependency.getArtifactId() );
218                setProperty( properties, "dependency." + i + ".groupId", dependency.getGroupId() );
219                setProperty( properties, "dependency." + i + ".version", dependency.getVersion() );
220                setProperty( properties, "dependency." + i + ".type", dependency.getType() );
221                setProperty( properties, "dependency." + i + ".optional", String.valueOf( dependency.isOptional() ) );
222
223                updateProjectReference( repoId, dependency.getGroupId(), dependency.getArtifactId(),
224                                        dependency.getVersion(), reference );
225
226                i++;
227            }
228            Set<String> facetIds = new LinkedHashSet<String>( versionMetadata.getFacetIds() );
229            facetIds.addAll( Arrays.asList( properties.getProperty( "facetIds", "" ).split( "," ) ) );
230            properties.setProperty( "facetIds", join( facetIds ) );
231
232            updateProjectVersionFacets( versionMetadata, properties );
233
234            writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
235        }
236        catch ( IOException e )
237        {
238            // TODO
239            log.error( e.getMessage(), e );
240        }
241    }
242
243    private void updateProjectVersionFacets( ProjectVersionMetadata versionMetadata, Properties properties )
244    {
245        for ( MetadataFacet facet : versionMetadata.getFacetList() )
246        {
247            for ( Map.Entry<String, String> entry : facet.toProperties().entrySet() )
248            {
249                properties.setProperty( facet.getFacetId() + ":" + entry.getKey(), entry.getValue() );
250            }
251        }
252    }
253
254    private static void clearMetadataFacetProperties( Collection<MetadataFacet> facetList, Properties properties,
255                                                      String prefix )
256    {
257        List<Object> propsToRemove = new ArrayList<>();
258        for ( MetadataFacet facet : facetList )
259        {
260            for ( Object key : new ArrayList( properties.keySet() ) )
261            {
262                String keyString = (String) key;
263                if ( keyString.startsWith( prefix + facet.getFacetId() + ":" ) )
264                {
265                    propsToRemove.add( key );
266                }
267            }
268        }
269
270        for ( Object key : propsToRemove )
271        {
272            properties.remove( key );
273        }
274    }
275
276    private void updateProjectReference( String repoId, String namespace, String projectId, String projectVersion,
277                                         ProjectVersionReference reference )
278    {
279        try
280        {
281            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
282
283            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
284            int i = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
285            setProperty( properties, "ref:lastReferenceNum", Integer.toString( i ) );
286            setProperty( properties, "ref:reference." + i + ".namespace", reference.getNamespace() );
287            setProperty( properties, "ref:reference." + i + ".projectId", reference.getProjectId() );
288            setProperty( properties, "ref:reference." + i + ".projectVersion", reference.getProjectVersion() );
289            setProperty( properties, "ref:reference." + i + ".referenceType", reference.getReferenceType().toString() );
290
291            writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
292        }
293        catch ( IOException e )
294        {
295            // TODO
296            log.error( e.getMessage(), e );
297        }
298    }
299
300    @Override
301    public void updateNamespace( String repoId, String namespace )
302    {
303        try
304        {
305            File namespaceDirectory = new File( getDirectory( repoId ), namespace );
306            Properties properties = new Properties();
307            properties.setProperty( "namespace", namespace );
308            writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
309
310        }
311        catch ( IOException e )
312        {
313            // TODO!
314            log.error( e.getMessage(), e );
315        }
316    }
317
318    @Override
319    public List<String> getMetadataFacets( String repoId, String facetId )
320        throws MetadataRepositoryException
321    {
322        try
323        {
324            File directory = getMetadataDirectory( repoId, facetId );
325            List<String> facets = new ArrayList<>();
326            recurse( facets, "", directory );
327            return facets;
328        }
329        catch ( IOException e )
330        {
331            throw new MetadataRepositoryException( e.getMessage(), e );
332        }
333    }
334
335    @Override
336    public boolean hasMetadataFacet( String repositoryId, String facetId )
337        throws MetadataRepositoryException
338    {
339        // TODO could be improved a bit
340        return !getMetadataFacets( repositoryId, facetId ).isEmpty();
341    }
342
343    private void recurse( List<String> facets, String prefix, File directory )
344    {
345        File[] list = directory.listFiles();
346        if ( list != null )
347        {
348            for ( File dir : list )
349            {
350                if ( dir.isDirectory() )
351                {
352                    recurse( facets, prefix + "/" + dir.getName(), dir );
353                }
354                else if ( dir.getName().equals( METADATA_KEY + ".properties" ) )
355                {
356                    facets.add( prefix.substring( 1 ) );
357                }
358            }
359        }
360    }
361
362    @Override
363    public MetadataFacet getMetadataFacet( String repositoryId, String facetId, String name )
364    {
365        Properties properties;
366        try
367        {
368            properties =
369                readProperties( new File( getMetadataDirectory( repositoryId, facetId ), name ), METADATA_KEY );
370        }
371        catch ( FileNotFoundException e )
372        {
373            return null;
374        }
375        catch ( IOException e )
376        {
377            // TODO
378            log.error( e.getMessage(), e );
379            return null;
380        }
381        MetadataFacet metadataFacet = null;
382        MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
383        if ( metadataFacetFactory != null )
384        {
385            metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
386            Map<String, String> map = new HashMap<>();
387            for ( Object key : new ArrayList( properties.keySet() ) )
388            {
389                String property = (String) key;
390                map.put( property, properties.getProperty( property ) );
391            }
392            metadataFacet.fromProperties( map );
393        }
394        return metadataFacet;
395    }
396
397    @Override
398    public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
399    {
400        Properties properties = new Properties();
401        properties.putAll( metadataFacet.toProperties() );
402
403        try
404        {
405            File directory =
406                new File( getMetadataDirectory( repositoryId, metadataFacet.getFacetId() ), metadataFacet.getName() );
407            writeProperties( properties, directory, METADATA_KEY );
408        }
409        catch ( IOException e )
410        {
411            // TODO!
412            log.error( e.getMessage(), e );
413        }
414    }
415
416    @Override
417    public void removeMetadataFacets( String repositoryId, String facetId )
418        throws MetadataRepositoryException
419    {
420        try
421        {
422            File dir = getMetadataDirectory( repositoryId, facetId );
423            FileUtils.deleteDirectory( dir );
424        }
425        catch ( IOException e )
426        {
427            throw new MetadataRepositoryException( e.getMessage(), e );
428        }
429    }
430
431    @Override
432    public void removeMetadataFacet( String repoId, String facetId, String name )
433        throws MetadataRepositoryException
434    {
435        try
436        {
437            File dir = new File( getMetadataDirectory( repoId, facetId ), name );
438            FileUtils.deleteDirectory( dir );
439        }
440        catch ( IOException e )
441        {
442            throw new MetadataRepositoryException( e.getMessage(), e );
443        }
444    }
445
446    @Override
447    public List<ArtifactMetadata> getArtifactsByDateRange( String repoId, Date startTime, Date endTime )
448        throws MetadataRepositoryException
449    {
450        try
451        {
452            // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
453            //  of this information (eg. in Lucene, as before)
454
455            List<ArtifactMetadata> artifacts = new ArrayList<>();
456            for ( String ns : getRootNamespaces( repoId ) )
457            {
458                getArtifactsByDateRange( artifacts, repoId, ns, startTime, endTime );
459            }
460            Collections.sort( artifacts, new ArtifactComparator() );
461            return artifacts;
462        }
463        catch ( MetadataResolutionException e )
464        {
465            throw new MetadataRepositoryException( e.getMessage(), e );
466        }
467    }
468
469    private void getArtifactsByDateRange( List<ArtifactMetadata> artifacts, String repoId, String ns, Date startTime,
470                                          Date endTime )
471        throws MetadataRepositoryException
472    {
473        try
474        {
475            for ( String namespace : getNamespaces( repoId, ns ) )
476            {
477                getArtifactsByDateRange( artifacts, repoId, ns + "." + namespace, startTime, endTime );
478            }
479
480            for ( String project : getProjects( repoId, ns ) )
481            {
482                for ( String version : getProjectVersions( repoId, ns, project ) )
483                {
484                    for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
485                    {
486                        if ( startTime == null || startTime.before( artifact.getWhenGathered() ) )
487                        {
488                            if ( endTime == null || endTime.after( artifact.getWhenGathered() ) )
489                            {
490                                artifacts.add( artifact );
491                            }
492                        }
493                    }
494                }
495            }
496        }
497        catch ( MetadataResolutionException e )
498        {
499            throw new MetadataRepositoryException( e.getMessage(), e );
500        }
501    }
502
503    @Override
504    public Collection<ArtifactMetadata> getArtifacts( String repoId, String namespace, String projectId,
505                                                      String projectVersion )
506        throws MetadataResolutionException
507    {
508        try
509        {
510            Map<String, ArtifactMetadata> artifacts = new HashMap<>();
511
512            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
513
514            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
515
516            for ( Map.Entry entry : properties.entrySet() )
517            {
518                String name = (String) entry.getKey();
519                StringTokenizer tok = new StringTokenizer( name, ":" );
520                if ( tok.hasMoreTokens() && "artifact".equals( tok.nextToken() ) )
521                {
522                    String field = tok.nextToken();
523                    String id = tok.nextToken();
524
525                    ArtifactMetadata artifact = artifacts.get( id );
526                    if ( artifact == null )
527                    {
528                        artifact = new ArtifactMetadata();
529                        artifact.setRepositoryId( repoId );
530                        artifact.setNamespace( namespace );
531                        artifact.setProject( projectId );
532                        artifact.setProjectVersion( projectVersion );
533                        artifact.setVersion( projectVersion );
534                        artifact.setId( id );
535                        artifacts.put( id, artifact );
536                    }
537
538                    String value = (String) entry.getValue();
539                    if ( "updated".equals( field ) )
540                    {
541                        artifact.setFileLastModified( Long.parseLong( value ) );
542                    }
543                    else if ( "size".equals( field ) )
544                    {
545                        artifact.setSize( Long.valueOf( value ) );
546                    }
547                    else if ( "whenGathered".equals( field ) )
548                    {
549                        artifact.setWhenGathered( new Date( Long.parseLong( value ) ) );
550                    }
551                    else if ( "version".equals( field ) )
552                    {
553                        artifact.setVersion( value );
554                    }
555                    else if ( "md5".equals( field ) )
556                    {
557                        artifact.setMd5( value );
558                    }
559                    else if ( "sha1".equals( field ) )
560                    {
561                        artifact.setSha1( value );
562                    }
563                    else if ( "facetIds".equals( field ) )
564                    {
565                        if ( value.length() > 0 )
566                        {
567                            String propertyPrefix = "artifact:facet:" + id + ":";
568                            for ( String facetId : value.split( "," ) )
569                            {
570                                MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
571                                if ( factory == null )
572                                {
573                                    log.error( "Attempted to load unknown artifact metadata facet: " + facetId );
574                                }
575                                else
576                                {
577                                    MetadataFacet facet = factory.createMetadataFacet();
578                                    String prefix = propertyPrefix + facet.getFacetId();
579                                    Map<String, String> map = new HashMap<>();
580                                    for ( Object key : new ArrayList( properties.keySet() ) )
581                                    {
582                                        String property = (String) key;
583                                        if ( property.startsWith( prefix ) )
584                                        {
585                                            map.put( property.substring( prefix.length() + 1 ),
586                                                     properties.getProperty( property ) );
587                                        }
588                                    }
589                                    facet.fromProperties( map );
590                                    artifact.addFacet( facet );
591                                }
592                            }
593                        }
594
595                        updateArtifactFacets( artifact, properties );
596                    }
597                }
598            }
599            return artifacts.values();
600        }
601        catch ( IOException e )
602        {
603            throw new MetadataResolutionException( e.getMessage(), e );
604        }
605    }
606
607    @Override
608    public void save()
609    {
610        // it's all instantly persisted
611    }
612
613    @Override
614    public void close()
615    {
616        // nothing additional to close
617    }
618
619    @Override
620    public void revert()
621    {
622        log.warn( "Attempted to revert a session, but the file-based repository storage doesn't support it" );
623    }
624
625    @Override
626    public boolean canObtainAccess( Class<?> aClass )
627    {
628        return false;
629    }
630
631    @Override
632    public <T> T obtainAccess( Class<T> aClass )
633    {
634        throw new IllegalArgumentException(
635            "Access using " + aClass + " is not supported on the file metadata storage" );
636    }
637
638    private void updateArtifactFacets( ArtifactMetadata artifact, Properties properties )
639    {
640        String propertyPrefix = "artifact:facet:" + artifact.getId() + ":";
641        for ( MetadataFacet facet : artifact.getFacetList() )
642        {
643            for ( Map.Entry<String, String> e : facet.toProperties().entrySet() )
644            {
645                String key = propertyPrefix + facet.getFacetId() + ":" + e.getKey();
646                properties.setProperty( key, e.getValue() );
647            }
648        }
649    }
650
651    @Override
652    public Collection<String> getRepositories()
653    {
654        List<String> repositories = new ArrayList<>();
655        for ( ManagedRepositoryConfiguration managedRepositoryConfiguration : configuration.getConfiguration().getManagedRepositories() )
656        {
657            repositories.add( managedRepositoryConfiguration.getId() );
658        }
659        return repositories;
660    }
661
662    @Override
663    public List<ArtifactMetadata> getArtifactsByChecksum( String repositoryId, String checksum )
664        throws MetadataRepositoryException
665    {
666        try
667        {
668            // TODO: this is quite slow - if we are to persist with this repository implementation we should build an index
669            //  of this information (eg. in Lucene, as before)
670            // alternatively, we could build a referential tree in the content repository, however it would need some levels
671            // of depth to avoid being too broad to be useful (eg. /repository/checksums/a/ab/abcdef1234567)
672
673            List<ArtifactMetadata> artifacts = new ArrayList<>();
674            for ( String ns : getRootNamespaces( repositoryId ) )
675            {
676                getArtifactsByChecksum( artifacts, repositoryId, ns, checksum );
677            }
678            return artifacts;
679        }
680        catch ( MetadataResolutionException e )
681        {
682            throw new MetadataRepositoryException( e.getMessage(), e );
683        }
684    }
685
686    @Override
687    public void removeNamespace( String repositoryId, String project )
688        throws MetadataRepositoryException
689    {
690        try
691        {
692            File namespaceDirectory = new File( getDirectory( repositoryId ), project );
693            FileUtils.deleteDirectory( namespaceDirectory );
694            //Properties properties = new Properties();
695            //properties.setProperty( "namespace", namespace );
696            //writeProperties( properties, namespaceDirectory, NAMESPACE_METADATA_KEY );
697
698        }
699        catch ( IOException e )
700        {
701            throw new MetadataRepositoryException( e.getMessage(), e );
702        }
703    }
704
705    @Override
706    public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
707        throws MetadataRepositoryException
708    {
709
710        try
711        {
712            File directory = new File( getDirectory( artifactMetadata.getRepositoryId() ),
713                                       artifactMetadata.getNamespace() + "/" + artifactMetadata.getProject() + "/"
714                                           + baseVersion );
715
716            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
717
718            String id = artifactMetadata.getId();
719
720            properties.remove( "artifact:updated:" + id );
721            properties.remove( "artifact:whenGathered:" + id );
722            properties.remove( "artifact:size:" + id );
723            properties.remove( "artifact:md5:" + id );
724            properties.remove( "artifact:sha1:" + id );
725            properties.remove( "artifact:version:" + id );
726            properties.remove( "artifact:facetIds:" + id );
727
728            String prefix = "artifact:facet:" + id + ":";
729            for ( Object key : new ArrayList( properties.keySet() ) )
730            {
731                String property = (String) key;
732                if ( property.startsWith( prefix ) )
733                {
734                    properties.remove( property );
735                }
736            }
737
738            writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
739        }
740        catch ( IOException e )
741        {
742            throw new MetadataRepositoryException( e.getMessage(), e );
743        }
744
745    }
746
747    @Override
748    public void removeArtifact( String repoId, String namespace, String project, String version, String id )
749        throws MetadataRepositoryException
750    {
751        try
752        {
753            File directory = new File( getDirectory( repoId ), namespace + "/" + project + "/" + version );
754
755            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
756
757            properties.remove( "artifact:updated:" + id );
758            properties.remove( "artifact:whenGathered:" + id );
759            properties.remove( "artifact:size:" + id );
760            properties.remove( "artifact:md5:" + id );
761            properties.remove( "artifact:sha1:" + id );
762            properties.remove( "artifact:version:" + id );
763            properties.remove( "artifact:facetIds:" + id );
764
765            String prefix = "artifact:facet:" + id + ":";
766            for ( Object key : new ArrayList( properties.keySet() ) )
767            {
768                String property = (String) key;
769                if ( property.startsWith( prefix ) )
770                {
771                    properties.remove( property );
772                }
773            }
774
775            FileUtils.deleteDirectory( directory );
776            //writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
777        }
778        catch ( IOException e )
779        {
780            throw new MetadataRepositoryException( e.getMessage(), e );
781        }
782    }
783
784    /**
785     * FIXME implements this !!!!
786     *
787     * @param repositoryId
788     * @param namespace
789     * @param project
790     * @param projectVersion
791     * @param metadataFacet  will remove artifacts which have this {@link MetadataFacet} using equals
792     * @throws MetadataRepositoryException
793     */
794    @Override
795    public void removeArtifact( String repositoryId, String namespace, String project, String projectVersion,
796                                MetadataFacet metadataFacet )
797        throws MetadataRepositoryException
798    {
799        throw new UnsupportedOperationException( "not implemented" );
800    }
801
802    @Override
803    public void removeRepository( String repoId )
804        throws MetadataRepositoryException
805    {
806        try
807        {
808            File dir = getDirectory( repoId );
809            FileUtils.deleteDirectory( dir );
810        }
811        catch ( IOException e )
812        {
813            throw new MetadataRepositoryException( e.getMessage(), e );
814        }
815    }
816
817    private void getArtifactsByChecksum( List<ArtifactMetadata> artifacts, String repositoryId, String ns,
818                                         String checksum )
819        throws MetadataRepositoryException
820    {
821        try
822        {
823            for ( String namespace : getNamespaces( repositoryId, ns ) )
824            {
825                getArtifactsByChecksum( artifacts, repositoryId, ns + "." + namespace, checksum );
826            }
827
828            for ( String project : getProjects( repositoryId, ns ) )
829            {
830                for ( String version : getProjectVersions( repositoryId, ns, project ) )
831                {
832                    for ( ArtifactMetadata artifact : getArtifacts( repositoryId, ns, project, version ) )
833                    {
834                        if ( checksum.equals( artifact.getMd5() ) || checksum.equals( artifact.getSha1() ) )
835                        {
836                            artifacts.add( artifact );
837                        }
838                    }
839                }
840            }
841        }
842        catch ( MetadataResolutionException e )
843        {
844            throw new MetadataRepositoryException( e.getMessage(), e );
845        }
846    }
847
848    @Override
849    public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
850        throws MetadataRepositoryException
851    {
852        throw new UnsupportedOperationException( "not yet implemented in File backend" );
853    }
854
855    @Override
856    public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
857        throws MetadataRepositoryException
858    {
859        throw new UnsupportedOperationException( "not yet implemented in File backend" );
860    }
861
862    @Override
863    public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
864        throws MetadataRepositoryException
865    {
866        throw new UnsupportedOperationException( "getArtifactsByProperty not yet implemented in File backend" );
867    }
868
869    private File getMetadataDirectory( String repoId, String facetId )
870        throws IOException
871    {
872        return new File( getBaseDirectory( repoId ), "facets/" + facetId );
873    }
874
875    private String join( Collection<String> ids )
876    {
877        if ( ids != null && !ids.isEmpty() )
878        {
879            StringBuilder s = new StringBuilder();
880            for ( String id : ids )
881            {
882                s.append( id );
883                s.append( "," );
884            }
885            return s.substring( 0, s.length() - 1 );
886        }
887        return "";
888    }
889
890    private void setProperty( Properties properties, String name, String value )
891    {
892        if ( value != null )
893        {
894            properties.setProperty( name, value );
895        }
896    }
897
898    @Override
899    public void updateArtifact( String repoId, String namespace, String projectId, String projectVersion,
900                                ArtifactMetadata artifact )
901    {
902        try
903        {
904            ProjectVersionMetadata metadata = new ProjectVersionMetadata();
905            metadata.setId( projectVersion );
906            updateProjectVersion( repoId, namespace, projectId, metadata );
907
908            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
909
910            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
911
912            clearMetadataFacetProperties( artifact.getFacetList(), properties,
913                                          "artifact:facet:" + artifact.getId() + ":" );
914
915            String id = artifact.getId();
916            properties.setProperty( "artifact:updated:" + id,
917                                    Long.toString( artifact.getFileLastModified().getTime() ) );
918            properties.setProperty( "artifact:whenGathered:" + id,
919                                    Long.toString( artifact.getWhenGathered().getTime() ) );
920            properties.setProperty( "artifact:size:" + id, Long.toString( artifact.getSize() ) );
921            if ( artifact.getMd5() != null )
922            {
923                properties.setProperty( "artifact:md5:" + id, artifact.getMd5() );
924            }
925            if ( artifact.getSha1() != null )
926            {
927                properties.setProperty( "artifact:sha1:" + id, artifact.getSha1() );
928            }
929            properties.setProperty( "artifact:version:" + id, artifact.getVersion() );
930
931            Set<String> facetIds = new LinkedHashSet<String>( artifact.getFacetIds() );
932            String property = "artifact:facetIds:" + id;
933            facetIds.addAll( Arrays.asList( properties.getProperty( property, "" ).split( "," ) ) );
934            properties.setProperty( property, join( facetIds ) );
935
936            updateArtifactFacets( artifact, properties );
937
938            writeProperties( properties, directory, PROJECT_VERSION_METADATA_KEY );
939        }
940        catch ( IOException e )
941        {
942            // TODO
943            log.error( e.getMessage(), e );
944        }
945    }
946
947    private Properties readOrCreateProperties( File directory, String propertiesKey )
948    {
949        try
950        {
951            return readProperties( directory, propertiesKey );
952        }
953        catch ( FileNotFoundException | NoSuchFileException e )
954        {
955            // ignore and return new properties
956        }
957        catch ( IOException e )
958        {
959            // TODO
960            log.error( e.getMessage(), e );
961        }
962        return new Properties();
963    }
964
965    private Properties readProperties( File directory, String propertiesKey )
966        throws IOException
967    {
968        Properties properties = new Properties();
969        try (InputStream in = Files.newInputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
970        {
971
972            properties.load( in );
973        }
974        return properties;
975    }
976
977    @Override
978    public ProjectMetadata getProject( String repoId, String namespace, String projectId )
979        throws MetadataResolutionException
980    {
981        try
982        {
983            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
984
985            Properties properties = readOrCreateProperties( directory, PROJECT_METADATA_KEY );
986
987            ProjectMetadata project = null;
988
989            String id = properties.getProperty( "id" );
990            if ( id != null )
991            {
992                project = new ProjectMetadata();
993                project.setNamespace( properties.getProperty( "namespace" ) );
994                project.setId( id );
995            }
996
997            return project;
998        }
999        catch ( IOException e )
1000        {
1001            throw new MetadataResolutionException( e.getMessage(), e );
1002        }
1003    }
1004
1005    @Override
1006    public ProjectVersionMetadata getProjectVersion( String repoId, String namespace, String projectId,
1007                                                     String projectVersion )
1008        throws MetadataResolutionException
1009    {
1010        try
1011        {
1012            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1013
1014            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1015            String id = properties.getProperty( "id" );
1016            ProjectVersionMetadata versionMetadata = null;
1017            if ( id != null )
1018            {
1019                versionMetadata = new ProjectVersionMetadata();
1020                versionMetadata.setId( id );
1021                versionMetadata.setName( properties.getProperty( "name" ) );
1022                versionMetadata.setDescription( properties.getProperty( "description" ) );
1023                versionMetadata.setUrl( properties.getProperty( "url" ) );
1024                versionMetadata.setIncomplete( Boolean.valueOf( properties.getProperty( "incomplete", "false" ) ) );
1025
1026                String scmConnection = properties.getProperty( "scm.connection" );
1027                String scmDeveloperConnection = properties.getProperty( "scm.developerConnection" );
1028                String scmUrl = properties.getProperty( "scm.url" );
1029                if ( scmConnection != null || scmDeveloperConnection != null || scmUrl != null )
1030                {
1031                    Scm scm = new Scm();
1032                    scm.setConnection( scmConnection );
1033                    scm.setDeveloperConnection( scmDeveloperConnection );
1034                    scm.setUrl( scmUrl );
1035                    versionMetadata.setScm( scm );
1036                }
1037
1038                String ciSystem = properties.getProperty( "ci.system" );
1039                String ciUrl = properties.getProperty( "ci.url" );
1040                if ( ciSystem != null || ciUrl != null )
1041                {
1042                    CiManagement ci = new CiManagement();
1043                    ci.setSystem( ciSystem );
1044                    ci.setUrl( ciUrl );
1045                    versionMetadata.setCiManagement( ci );
1046                }
1047
1048                String issueSystem = properties.getProperty( "issue.system" );
1049                String issueUrl = properties.getProperty( "issue.url" );
1050                if ( issueSystem != null || issueUrl != null )
1051                {
1052                    IssueManagement issueManagement = new IssueManagement();
1053                    issueManagement.setSystem( issueSystem );
1054                    issueManagement.setUrl( issueUrl );
1055                    versionMetadata.setIssueManagement( issueManagement );
1056                }
1057
1058                String orgName = properties.getProperty( "org.name" );
1059                String orgUrl = properties.getProperty( "org.url" );
1060                if ( orgName != null || orgUrl != null )
1061                {
1062                    Organization org = new Organization();
1063                    org.setName( orgName );
1064                    org.setUrl( orgUrl );
1065                    versionMetadata.setOrganization( org );
1066                }
1067
1068                boolean done = false;
1069                int i = 0;
1070                while ( !done )
1071                {
1072                    String licenseName = properties.getProperty( "license." + i + ".name" );
1073                    String licenseUrl = properties.getProperty( "license." + i + ".url" );
1074                    if ( licenseName != null || licenseUrl != null )
1075                    {
1076                        License license = new License();
1077                        license.setName( licenseName );
1078                        license.setUrl( licenseUrl );
1079                        versionMetadata.addLicense( license );
1080                    }
1081                    else
1082                    {
1083                        done = true;
1084                    }
1085                    i++;
1086                }
1087
1088                done = false;
1089                i = 0;
1090                while ( !done )
1091                {
1092                    String mailingListName = properties.getProperty( "mailingList." + i + ".name" );
1093                    if ( mailingListName != null )
1094                    {
1095                        MailingList mailingList = new MailingList();
1096                        mailingList.setName( mailingListName );
1097                        mailingList.setMainArchiveUrl( properties.getProperty( "mailingList." + i + ".archive" ) );
1098                        String p = properties.getProperty( "mailingList." + i + ".otherArchives" );
1099                        if ( p != null && p.length() > 0 )
1100                        {
1101                            mailingList.setOtherArchives( Arrays.asList( p.split( "," ) ) );
1102                        }
1103                        else
1104                        {
1105                            mailingList.setOtherArchives( Collections.<String>emptyList() );
1106                        }
1107                        mailingList.setPostAddress( properties.getProperty( "mailingList." + i + ".post" ) );
1108                        mailingList.setSubscribeAddress( properties.getProperty( "mailingList." + i + ".subscribe" ) );
1109                        mailingList.setUnsubscribeAddress(
1110                            properties.getProperty( "mailingList." + i + ".unsubscribe" ) );
1111                        versionMetadata.addMailingList( mailingList );
1112                    }
1113                    else
1114                    {
1115                        done = true;
1116                    }
1117                    i++;
1118                }
1119
1120                done = false;
1121                i = 0;
1122                while ( !done )
1123                {
1124                    String dependencyArtifactId = properties.getProperty( "dependency." + i + ".artifactId" );
1125                    if ( dependencyArtifactId != null )
1126                    {
1127                        Dependency dependency = new Dependency();
1128                        dependency.setArtifactId( dependencyArtifactId );
1129                        dependency.setGroupId( properties.getProperty( "dependency." + i + ".groupId" ) );
1130                        dependency.setClassifier( properties.getProperty( "dependency." + i + ".classifier" ) );
1131                        dependency.setOptional(
1132                            Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1133                        dependency.setScope( properties.getProperty( "dependency." + i + ".scope" ) );
1134                        dependency.setSystemPath( properties.getProperty( "dependency." + i + ".systemPath" ) );
1135                        dependency.setType( properties.getProperty( "dependency." + i + ".type" ) );
1136                        dependency.setVersion( properties.getProperty( "dependency." + i + ".version" ) );
1137                        dependency.setOptional(
1138                            Boolean.valueOf( properties.getProperty( "dependency." + i + ".optional" ) ) );
1139                        versionMetadata.addDependency( dependency );
1140                    }
1141                    else
1142                    {
1143                        done = true;
1144                    }
1145                    i++;
1146                }
1147
1148                String facetIds = properties.getProperty( "facetIds", "" );
1149                if ( facetIds.length() > 0 )
1150                {
1151                    for ( String facetId : facetIds.split( "," ) )
1152                    {
1153                        MetadataFacetFactory factory = metadataFacetFactories.get( facetId );
1154                        if ( factory == null )
1155                        {
1156                            log.error( "Attempted to load unknown project version metadata facet: {}", facetId );
1157                        }
1158                        else
1159                        {
1160                            MetadataFacet facet = factory.createMetadataFacet();
1161                            Map<String, String> map = new HashMap<>();
1162                            for ( Object key : new ArrayList( properties.keySet() ) )
1163                            {
1164                                String property = (String) key;
1165                                if ( property.startsWith( facet.getFacetId() ) )
1166                                {
1167                                    map.put( property.substring( facet.getFacetId().length() + 1 ),
1168                                             properties.getProperty( property ) );
1169                                }
1170                            }
1171                            facet.fromProperties( map );
1172                            versionMetadata.addFacet( facet );
1173                        }
1174                    }
1175                }
1176
1177                updateProjectVersionFacets( versionMetadata, properties );
1178            }
1179            return versionMetadata;
1180        }
1181        catch ( IOException e )
1182        {
1183            throw new MetadataResolutionException( e.getMessage(), e );
1184        }
1185    }
1186
1187    @Override
1188    public Collection<String> getArtifactVersions( String repoId, String namespace, String projectId,
1189                                                   String projectVersion )
1190        throws MetadataResolutionException
1191    {
1192        try
1193        {
1194            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1195
1196            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1197
1198            Set<String> versions = new HashSet<String>();
1199            for ( Map.Entry entry : properties.entrySet() )
1200            {
1201                String name = (String) entry.getKey();
1202                if ( name.startsWith( "artifact:version:" ) )
1203                {
1204                    versions.add( (String) entry.getValue() );
1205                }
1206            }
1207            return versions;
1208        }
1209        catch ( IOException e )
1210        {
1211            throw new MetadataResolutionException( e.getMessage(), e );
1212        }
1213    }
1214
1215    @Override
1216    public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
1217                                                                     String projectVersion )
1218        throws MetadataResolutionException
1219    {
1220        try
1221        {
1222            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1223
1224            Properties properties = readOrCreateProperties( directory, PROJECT_VERSION_METADATA_KEY );
1225            int numberOfRefs = Integer.parseInt( properties.getProperty( "ref:lastReferenceNum", "-1" ) ) + 1;
1226
1227            List<ProjectVersionReference> references = new ArrayList<>();
1228            for ( int i = 0; i < numberOfRefs; i++ )
1229            {
1230                ProjectVersionReference reference = new ProjectVersionReference();
1231                reference.setProjectId( properties.getProperty( "ref:reference." + i + ".projectId" ) );
1232                reference.setNamespace( properties.getProperty( "ref:reference." + i + ".namespace" ) );
1233                reference.setProjectVersion( properties.getProperty( "ref:reference." + i + ".projectVersion" ) );
1234                reference.setReferenceType( ProjectVersionReference.ReferenceType.valueOf(
1235                    properties.getProperty( "ref:reference." + i + ".referenceType" ) ) );
1236                references.add( reference );
1237            }
1238            return references;
1239        }
1240        catch ( IOException e )
1241        {
1242            throw new MetadataResolutionException( e.getMessage(), e );
1243        }
1244    }
1245
1246    @Override
1247    public Collection<String> getRootNamespaces( String repoId )
1248        throws MetadataResolutionException
1249    {
1250        return getNamespaces( repoId, null );
1251    }
1252
1253    @Override
1254    public Collection<String> getNamespaces( String repoId, String baseNamespace )
1255        throws MetadataResolutionException
1256    {
1257        try
1258        {
1259            List<String> allNamespaces = new ArrayList<>();
1260            File directory = getDirectory( repoId );
1261            File[] files = directory.listFiles();
1262            if ( files != null )
1263            {
1264                for ( File namespace : files )
1265                {
1266                    if ( new File( namespace, NAMESPACE_METADATA_KEY + ".properties" ).exists() )
1267                    {
1268                        allNamespaces.add( namespace.getName() );
1269                    }
1270                }
1271            }
1272
1273            Set<String> namespaces = new LinkedHashSet<>();
1274            int fromIndex = baseNamespace != null ? baseNamespace.length() + 1 : 0;
1275            for ( String namespace : allNamespaces )
1276            {
1277                if ( baseNamespace == null || namespace.startsWith( baseNamespace + "." ) )
1278                {
1279                    int i = namespace.indexOf( '.', fromIndex );
1280                    if ( i >= 0 )
1281                    {
1282                        namespaces.add( namespace.substring( fromIndex, i ) );
1283                    }
1284                    else
1285                    {
1286                        namespaces.add( namespace.substring( fromIndex ) );
1287                    }
1288                }
1289            }
1290            return new ArrayList<>( namespaces );
1291        }
1292        catch ( IOException e )
1293        {
1294            throw new MetadataResolutionException( e.getMessage(), e );
1295        }
1296    }
1297
1298    @Override
1299    public Collection<String> getProjects( String repoId, String namespace )
1300        throws MetadataResolutionException
1301    {
1302        try
1303        {
1304            List<String> projects = new ArrayList<>();
1305            File directory = new File( getDirectory( repoId ), namespace );
1306            File[] files = directory.listFiles();
1307            if ( files != null )
1308            {
1309                for ( File project : files )
1310                {
1311                    if ( new File( project, PROJECT_METADATA_KEY + ".properties" ).exists() )
1312                    {
1313                        projects.add( project.getName() );
1314                    }
1315                }
1316            }
1317            return projects;
1318        }
1319        catch ( IOException e )
1320        {
1321            throw new MetadataResolutionException( e.getMessage(), e );
1322        }
1323    }
1324
1325    @Override
1326    public Collection<String> getProjectVersions( String repoId, String namespace, String projectId )
1327        throws MetadataResolutionException
1328    {
1329        try
1330        {
1331            List<String> projectVersions = new ArrayList<>();
1332            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId );
1333            File[] files = directory.listFiles();
1334            if ( files != null )
1335            {
1336                for ( File projectVersion : files )
1337                {
1338                    if ( new File( projectVersion, PROJECT_VERSION_METADATA_KEY + ".properties" ).exists() )
1339                    {
1340                        projectVersions.add( projectVersion.getName() );
1341                    }
1342                }
1343            }
1344            return projectVersions;
1345        }
1346        catch ( IOException e )
1347        {
1348            throw new MetadataResolutionException( e.getMessage(), e );
1349        }
1350    }
1351
1352    @Override
1353    public void removeProject( String repositoryId, String namespace, String projectId )
1354        throws MetadataRepositoryException
1355    {
1356        try
1357        {
1358            File directory = new File( getDirectory( repositoryId ), namespace + "/" + projectId );
1359            FileUtils.deleteDirectory( directory );
1360        }
1361        catch ( IOException e )
1362        {
1363            throw new MetadataRepositoryException( e.getMessage(), e );
1364        }
1365    }
1366
1367    @Override
1368    public void removeProjectVersion( String repoId, String namespace, String projectId, String projectVersion )
1369        throws MetadataRepositoryException
1370    {
1371        try
1372        {
1373            File directory = new File( getDirectory( repoId ), namespace + "/" + projectId + "/" + projectVersion );
1374            FileUtils.deleteDirectory( directory );
1375        }
1376        catch ( IOException e )
1377        {
1378            throw new MetadataRepositoryException( e.getMessage(), e );
1379        }
1380
1381    }
1382
1383    private void writeProperties( Properties properties, File directory, String propertiesKey )
1384        throws IOException
1385    {
1386        directory.mkdirs();
1387        try (OutputStream os = Files.newOutputStream( new File( directory, propertiesKey + ".properties" ).toPath() ))
1388        {
1389            properties.store( os, null );
1390        }
1391    }
1392
1393    private static class ArtifactComparator
1394        implements Comparator<ArtifactMetadata>
1395    {
1396        @Override
1397        public int compare( ArtifactMetadata artifact1, ArtifactMetadata artifact2 )
1398        {
1399            if ( artifact1.getWhenGathered() == artifact2.getWhenGathered() )
1400            {
1401                return 0;
1402            }
1403            if ( artifact1.getWhenGathered() == null )
1404            {
1405                return 1;
1406            }
1407            if ( artifact2.getWhenGathered() == null )
1408            {
1409                return -1;
1410            }
1411            return artifact1.getWhenGathered().compareTo( artifact2.getWhenGathered() );
1412        }
1413    }
1414
1415    @Override
1416    public List<ArtifactMetadata> getArtifacts( String repoId )
1417        throws MetadataRepositoryException
1418    {
1419        try
1420        {
1421            List<ArtifactMetadata> artifacts = new ArrayList<>();
1422            for ( String ns : getRootNamespaces( repoId ) )
1423            {
1424                getArtifacts( artifacts, repoId, ns );
1425            }
1426            return artifacts;
1427        }
1428        catch ( MetadataResolutionException e )
1429        {
1430            throw new MetadataRepositoryException( e.getMessage(), e );
1431        }
1432    }
1433
1434    private void getArtifacts( List<ArtifactMetadata> artifacts, String repoId, String ns )
1435        throws MetadataResolutionException
1436    {
1437        for ( String namespace : getNamespaces( repoId, ns ) )
1438        {
1439            getArtifacts( artifacts, repoId, ns + "." + namespace );
1440        }
1441
1442        for ( String project : getProjects( repoId, ns ) )
1443        {
1444            for ( String version : getProjectVersions( repoId, ns, project ) )
1445            {
1446                for ( ArtifactMetadata artifact : getArtifacts( repoId, ns, project, version ) )
1447                {
1448                    artifacts.add( artifact );
1449                }
1450            }
1451        }
1452    }
1453
1454    @Override
1455    public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
1456        throws MetadataRepositoryException
1457    {
1458        throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1459    }
1460
1461    @Override
1462    public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
1463        throws MetadataRepositoryException
1464    {
1465        throw new UnsupportedOperationException( "searchArtifacts not yet implemented in File backend" );
1466    }
1467}