This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.metadata.repository.cassandra;
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 com.google.common.base.Predicate;
023import com.google.common.collect.Iterables;
024
025import me.prettyprint.cassandra.serializers.LongSerializer;
026import me.prettyprint.cassandra.serializers.StringSerializer;
027import me.prettyprint.cassandra.service.template.ColumnFamilyResult;
028import me.prettyprint.cassandra.service.template.ColumnFamilyTemplate;
029import me.prettyprint.cassandra.service.template.ColumnFamilyUpdater;
030import me.prettyprint.cassandra.service.template.ThriftColumnFamilyTemplate;
031import me.prettyprint.hector.api.Keyspace;
032import me.prettyprint.hector.api.beans.ColumnSlice;
033import me.prettyprint.hector.api.beans.OrderedRows;
034import me.prettyprint.hector.api.beans.Row;
035import me.prettyprint.hector.api.exceptions.HInvalidRequestException;
036import me.prettyprint.hector.api.factory.HFactory;
037import me.prettyprint.hector.api.mutation.MutationResult;
038import me.prettyprint.hector.api.mutation.Mutator;
039import me.prettyprint.hector.api.query.QueryResult;
040import me.prettyprint.hector.api.query.RangeSlicesQuery;
041
042import org.apache.archiva.configuration.ArchivaConfiguration;
043import org.apache.archiva.metadata.model.ArtifactMetadata;
044import org.apache.archiva.metadata.model.CiManagement;
045import org.apache.archiva.metadata.model.Dependency;
046import org.apache.archiva.metadata.model.FacetedMetadata;
047import org.apache.archiva.metadata.model.IssueManagement;
048import org.apache.archiva.metadata.model.License;
049import org.apache.archiva.metadata.model.MailingList;
050import org.apache.archiva.metadata.model.MetadataFacet;
051import org.apache.archiva.metadata.model.MetadataFacetFactory;
052import org.apache.archiva.metadata.model.Organization;
053import org.apache.archiva.metadata.model.ProjectMetadata;
054import org.apache.archiva.metadata.model.ProjectVersionMetadata;
055import org.apache.archiva.metadata.model.ProjectVersionReference;
056import org.apache.archiva.metadata.model.Scm;
057import org.apache.archiva.metadata.repository.MetadataRepository;
058import org.apache.archiva.metadata.repository.MetadataRepositoryException;
059import org.apache.archiva.metadata.repository.MetadataResolutionException;
060import org.apache.archiva.metadata.repository.cassandra.model.ArtifactMetadataModel;
061import org.apache.archiva.metadata.repository.cassandra.model.MetadataFacetModel;
062import org.apache.archiva.metadata.repository.cassandra.model.Namespace;
063import org.apache.archiva.metadata.repository.cassandra.model.Project;
064import org.apache.archiva.metadata.repository.cassandra.model.ProjectVersionMetadataModel;
065import org.apache.archiva.metadata.repository.cassandra.model.Repository;
066import org.apache.commons.lang.StringUtils;
067import org.modelmapper.ModelMapper;
068import org.slf4j.Logger;
069import org.slf4j.LoggerFactory;
070
071import javax.persistence.PersistenceException;
072
073import java.util.ArrayList;
074import java.util.Collection;
075import java.util.Collections;
076import java.util.Date;
077import java.util.HashMap;
078import java.util.HashSet;
079import java.util.Iterator;
080import java.util.LinkedList;
081import java.util.List;
082import java.util.Map;
083import java.util.Set;
084import java.util.UUID;
085
086import static org.apache.archiva.metadata.repository.cassandra.CassandraUtils.*;
087import static org.apache.archiva.metadata.repository.cassandra.model.ColumnNames.*;
088
089/**
090 * @author Olivier Lamy
091 * @since 2.0.0
092 */
093public class CassandraMetadataRepository
094    implements MetadataRepository
095{
096
097    private Logger logger = LoggerFactory.getLogger( getClass() );
098
099    private ArchivaConfiguration configuration;
100
101    private final Map<String, MetadataFacetFactory> metadataFacetFactories;
102
103    private final CassandraArchivaManager cassandraArchivaManager;
104
105    private final ColumnFamilyTemplate<String, String> projectVersionMetadataTemplate;
106
107    private final ColumnFamilyTemplate<String, String> projectTemplate;
108
109    private final ColumnFamilyTemplate<String, String> artifactMetadataTemplate;
110
111    private final ColumnFamilyTemplate<String, String> metadataFacetTemplate;
112
113    private final ColumnFamilyTemplate<String, String> mailingListTemplate;
114
115    private final ColumnFamilyTemplate<String, String> licenseTemplate;
116
117    private final ColumnFamilyTemplate<String, String> dependencyTemplate;
118
119    private final Keyspace keyspace;
120
121    private final StringSerializer ss = StringSerializer.get();
122
123    public CassandraMetadataRepository( Map<String, MetadataFacetFactory> metadataFacetFactories,
124                                        ArchivaConfiguration configuration,
125                                        CassandraArchivaManager cassandraArchivaManager )
126    {
127        this.metadataFacetFactories = metadataFacetFactories;
128        this.configuration = configuration;
129        this.cassandraArchivaManager = cassandraArchivaManager;
130        this.keyspace = cassandraArchivaManager.getKeyspace();
131
132        this.projectVersionMetadataTemplate =
133            new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
134                                              cassandraArchivaManager.getProjectVersionMetadataFamilyName(), //
135                                              StringSerializer.get(), //
136                                              StringSerializer.get() );
137
138        this.projectTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
139                                                                 cassandraArchivaManager.getProjectFamilyName(), //
140                                                                 //
141                                                                 StringSerializer.get(), //
142                                                                 StringSerializer.get() );
143
144        this.artifactMetadataTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
145                                                                          cassandraArchivaManager.getArtifactMetadataFamilyName(),
146                                                                          StringSerializer.get(), //
147                                                                          StringSerializer.get() );
148
149        this.metadataFacetTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
150                                                                       cassandraArchivaManager.getMetadataFacetFamilyName(),
151                                                                       //
152                                                                       StringSerializer.get(), //
153                                                                       StringSerializer.get() );
154
155        this.mailingListTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
156                                                                     cassandraArchivaManager.getMailingListFamilyName(),
157                                                                     //
158                                                                     StringSerializer.get(), //
159                                                                     StringSerializer.get() );
160
161        this.licenseTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
162                                                                 cassandraArchivaManager.getLicenseFamilyName(),
163                                                                 //
164                                                                 StringSerializer.get(), //
165                                                                 StringSerializer.get() );
166
167        this.dependencyTemplate = new ThriftColumnFamilyTemplate<>( cassandraArchivaManager.getKeyspace(), //
168                                                                    cassandraArchivaManager.getDependencyFamilyName(),
169                                                                    //
170                                                                    StringSerializer.get(), //
171                                                                    StringSerializer.get() );
172    }
173
174
175    /**
176     * if the repository doesn't exist it will be created
177     *
178     * @param repositoryId
179     * @return
180     */
181    public Repository getOrCreateRepository( String repositoryId )
182        throws MetadataRepositoryException
183    {
184        String cf = cassandraArchivaManager.getRepositoryFamilyName();
185
186        QueryResult<OrderedRows<String, String, String>> result = HFactory //
187            .createRangeSlicesQuery( keyspace, StringSerializer.get(), StringSerializer.get(),
188                                     StringSerializer.get() ) //
189            .setColumnFamily( cf ) //
190            .setColumnNames( REPOSITORY_NAME.toString() ) //
191            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
192            .execute();
193
194        if ( result.get().getCount() < 1 )
195        {
196            // we need to create the repository
197            Repository repository = new Repository( repositoryId );
198
199            try
200            {
201                MutationResult mutationResult = HFactory.createMutator( keyspace, StringSerializer.get() ) //
202                    .addInsertion( repositoryId, cf,
203                                   CassandraUtils.column( REPOSITORY_NAME.toString(), repository.getName() ) ) //
204                    .execute();
205                logger.debug( "time to insert repository: {}", mutationResult.getExecutionTimeMicro() );
206                return repository;
207            }
208            catch ( HInvalidRequestException e )
209            {
210                logger.error( e.getMessage(), e );
211                throw new MetadataRepositoryException( e.getMessage(), e );
212            }
213
214        }
215
216        return new Repository(
217            result.get().getList().get( 0 ).getColumnSlice().getColumnByName( REPOSITORY_NAME.toString() ).getValue() );
218    }
219
220
221    protected Repository getRepository( String repositoryId )
222        throws MetadataRepositoryException
223    {
224
225        QueryResult<OrderedRows<String, String, String>> result = HFactory //
226            .createRangeSlicesQuery( keyspace, StringSerializer.get(), StringSerializer.get(),
227                                     StringSerializer.get() ) //
228            .setColumnFamily( cassandraArchivaManager.getRepositoryFamilyName() ) //
229            .setColumnNames( REPOSITORY_NAME.toString() ) //
230            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
231            .execute();
232        return ( result.get().getCount() > 0 ) ? new Repository( repositoryId ) : null;
233    }
234
235    @Override
236    public void updateNamespace( String repositoryId, String namespaceId )
237        throws MetadataRepositoryException
238    {
239        updateOrAddNamespace( repositoryId, namespaceId );
240    }
241
242    private Namespace updateOrAddNamespace( String repositoryId, String namespaceId )
243        throws MetadataRepositoryException
244    {
245        try
246        {
247            Repository repository = getOrCreateRepository( repositoryId );
248
249            String key =
250                new Namespace.KeyBuilder().withNamespace( namespaceId ).withRepositoryId( repositoryId ).build();
251
252            Namespace namespace = getNamespace( repositoryId, namespaceId );
253            if ( namespace == null )
254            {
255                String cf = cassandraArchivaManager.getNamespaceFamilyName();
256                namespace = new Namespace( namespaceId, repository );
257                HFactory.createMutator( keyspace, StringSerializer.get() )
258                    //  values
259                    .addInsertion( key, cf, CassandraUtils.column( NAME.toString(), namespace.getName() ) ) //
260                    .addInsertion( key, cf, CassandraUtils.column( REPOSITORY_NAME.toString(), repository.getName() ) ) //
261                    .execute();
262            }
263
264            return namespace;
265        }
266        catch ( HInvalidRequestException e )
267        {
268            logger.error( e.getMessage(), e );
269            throw new MetadataRepositoryException( e.getMessage(), e );
270        }
271    }
272
273    protected Namespace getNamespace( String repositoryId, String namespaceId )
274    {
275
276        QueryResult<OrderedRows<String, String, String>> result = HFactory //
277            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
278            .setColumnFamily( cassandraArchivaManager.getNamespaceFamilyName() ) //
279            .setColumnNames( REPOSITORY_NAME.toString(), NAME.toString() ) //
280            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
281            .addEqualsExpression( NAME.toString(), namespaceId ) //
282            .execute();
283        if ( result.get().getCount() > 0 )
284        {
285            ColumnSlice<String, String> columnSlice = result.get().getList().get( 0 ).getColumnSlice();
286            return new Namespace( getStringValue( columnSlice, NAME.toString() ), //
287                                  new Repository( getStringValue( columnSlice, REPOSITORY_NAME.toString() ) ) );
288
289        }
290        return null;
291    }
292
293
294    @Override
295    public void removeNamespace( String repositoryId, String namespaceId )
296        throws MetadataRepositoryException
297    {
298
299        try
300        {
301            String key = new Namespace.KeyBuilder() //
302                .withNamespace( namespaceId ) //
303                .withRepositoryId( repositoryId ) //
304                .build();
305
306            HFactory.createMutator( cassandraArchivaManager.getKeyspace(), new StringSerializer() ) //
307                .addDeletion( key, cassandraArchivaManager.getNamespaceFamilyName() ) //
308                .execute();
309
310            QueryResult<OrderedRows<String, String, String>> result = HFactory //
311                .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
312                .setColumnFamily( cassandraArchivaManager.getProjectFamilyName() ) //
313                .setColumnNames( REPOSITORY_NAME.toString() ) //
314                .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
315                .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
316                .execute();
317
318            for ( Row<String, String, String> row : result.get() )
319            {
320                this.projectTemplate.deleteRow( row.getKey() );
321            }
322
323            result = HFactory //
324                .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
325                .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
326                .setColumnNames( REPOSITORY_NAME.toString() ) //
327                .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
328                .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
329                .execute();
330
331            for ( Row<String, String, String> row : result.get() )
332            {
333                this.projectVersionMetadataTemplate.deleteRow( row.getKey() );
334                removeMailingList( row.getKey() );
335            }
336
337            result = HFactory //
338                .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
339                .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
340                .setColumnNames( REPOSITORY_NAME.toString() ) //
341                .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
342                .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
343                .execute();
344
345            for ( Row<String, String, String> row : result.get() )
346            {
347                this.artifactMetadataTemplate.deleteRow( row.getKey() );
348            }
349
350            result = HFactory //
351                .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
352                .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
353                .setColumnNames( REPOSITORY_NAME.toString() ) //
354                .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
355                .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
356                .execute();
357
358            for ( Row<String, String, String> row : result.get() )
359            {
360                this.metadataFacetTemplate.deleteRow( row.getKey() );
361            }
362
363        }
364        catch ( HInvalidRequestException e )
365        {
366            logger.error( e.getMessage(), e );
367            throw new MetadataRepositoryException( e.getMessage(), e );
368        }
369    }
370
371
372    @Override
373    public void removeRepository( final String repositoryId )
374        throws MetadataRepositoryException
375    {
376
377        // TODO use cql queries to delete all
378        List<String> namespacesKey = new ArrayList<>();
379
380        QueryResult<OrderedRows<String, String, String>> result = HFactory //
381            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
382            .setColumnFamily( cassandraArchivaManager.getNamespaceFamilyName() ) //
383            .setColumnNames( REPOSITORY_NAME.toString() ) //
384            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
385            .execute();
386
387        for ( Row<String, String, String> row : result.get().getList() )
388        {
389            namespacesKey.add( row.getKey() );
390        }
391
392        HFactory.createMutator( cassandraArchivaManager.getKeyspace(), ss ) //
393            .addDeletion( namespacesKey, cassandraArchivaManager.getNamespaceFamilyName() ) //
394            .execute();
395
396        //delete repositoryId
397        HFactory.createMutator( cassandraArchivaManager.getKeyspace(), ss ) //
398            .addDeletion( repositoryId, cassandraArchivaManager.getRepositoryFamilyName() ) //
399            .execute();
400
401        result = HFactory //
402            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
403            .setColumnFamily( cassandraArchivaManager.getProjectFamilyName() ) //
404            .setColumnNames( REPOSITORY_NAME.toString() ) //
405            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
406            .execute();
407
408        for ( Row<String, String, String> row : result.get() )
409        {
410            this.projectTemplate.deleteRow( row.getKey() );
411        }
412
413        result = HFactory //
414            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
415            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
416            .setColumnNames( REPOSITORY_NAME.toString() ) //
417            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
418            .execute();
419
420        for ( Row<String, String, String> row : result.get() )
421        {
422            this.projectVersionMetadataTemplate.deleteRow( row.getKey() );
423            removeMailingList( row.getKey() );
424        }
425
426        result = HFactory //
427            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
428            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
429            .setColumnNames( REPOSITORY_NAME.toString() ) //
430            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
431            .execute();
432
433        for ( Row<String, String, String> row : result.get() )
434        {
435            this.artifactMetadataTemplate.deleteRow( row.getKey() );
436        }
437
438        result = HFactory //
439            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
440            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
441            .setColumnNames( REPOSITORY_NAME.toString() ) //
442            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
443            .execute();
444
445        for ( Row<String, String, String> row : result.get() )
446        {
447            this.metadataFacetTemplate.deleteRow( row.getKey() );
448        }
449
450
451    }
452
453    @Override
454    public Collection<String> getRepositories()
455        throws MetadataRepositoryException
456    {
457        try
458        {
459            logger.debug( "getRepositories" );
460
461            final QueryResult<OrderedRows<String, String, String>> cResult = //
462                HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), //
463                                                 ss, ss, ss ) //
464                    .setColumnFamily( cassandraArchivaManager.getRepositoryFamilyName() ) //
465                    .setColumnNames( REPOSITORY_NAME.toString() ) //
466                    .setRange( null, null, false, Integer.MAX_VALUE ) //
467                    .execute();
468
469            List<String> repoIds = new ArrayList<>( cResult.get().getCount() );
470
471            for ( Row<String, String, String> row : cResult.get() )
472            {
473                repoIds.add( getStringValue( row.getColumnSlice(), REPOSITORY_NAME.toString() ) );
474            }
475
476            return repoIds;
477        }
478        catch ( PersistenceException e )
479        {
480            throw new MetadataRepositoryException( e.getMessage(), e );
481        }
482
483    }
484
485    // FIXME this one need peformance improvement maybe a cache?
486    @Override
487    public Collection<String> getRootNamespaces( final String repoId )
488        throws MetadataResolutionException
489    {
490
491        QueryResult<OrderedRows<String, String, String>> result = HFactory //
492            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
493            .setColumnFamily( cassandraArchivaManager.getNamespaceFamilyName() ) //
494            .setColumnNames( NAME.toString() ) //
495            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
496            .execute();
497
498        Set<String> namespaces = new HashSet<String>( result.get().getCount() );
499
500        for ( Row<String, String, String> row : result.get() )
501        {
502            namespaces.add( StringUtils.substringBefore( getStringValue( row.getColumnSlice(), NAME.toString() ), "." ) );
503        }
504
505        return namespaces;
506    }
507
508    // FIXME this one need peformance improvement maybe a cache?
509    @Override
510    public Collection<String> getNamespaces( final String repoId, final String namespaceId )
511        throws MetadataResolutionException
512    {
513
514        QueryResult<OrderedRows<String, String, String>> result = HFactory //
515            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
516            .setColumnFamily( cassandraArchivaManager.getNamespaceFamilyName() ) //
517            .setColumnNames( NAME.toString() ) //
518            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
519            .execute();
520
521        List<String> namespaces = new ArrayList<>( result.get().getCount() );
522
523        for ( Row<String, String, String> row : result.get() )
524        {
525            String currentNamespace = getStringValue( row.getColumnSlice(), NAME.toString() );
526            if ( StringUtils.startsWith( currentNamespace, namespaceId ) //
527                && ( StringUtils.length( currentNamespace ) > StringUtils.length( namespaceId ) ) )
528            {
529                // store after namespaceId '.' but before next '.'
530                // call org namespace org.apache.maven.shared -> stored apache
531
532                String calledNamespace = StringUtils.endsWith( namespaceId, "." ) ? namespaceId : namespaceId + ".";
533                String storedNamespace = StringUtils.substringAfter( currentNamespace, calledNamespace );
534
535                storedNamespace = StringUtils.substringBefore( storedNamespace, "." );
536
537                namespaces.add( storedNamespace );
538            }
539        }
540
541        return namespaces;
542
543    }
544
545    // only use for testing purpose
546    protected List<String> getNamespaces( final String repoId )
547        throws MetadataResolutionException
548    {
549
550        QueryResult<OrderedRows<String, String, String>> result = HFactory //
551            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
552            .setColumnFamily( cassandraArchivaManager.getNamespaceFamilyName() ) //
553            .setColumnNames( NAME.toString() ) //
554            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
555            .execute();
556
557        List<String> namespaces = new ArrayList<>( result.get().getCount() );
558
559        for ( Row<String, String, String> row : result.get() )
560        {
561            namespaces.add( getStringValue( row.getColumnSlice(), NAME.toString() ) );
562        }
563
564        return namespaces;
565    }
566
567
568    @Override
569    public void updateProject( String repositoryId, ProjectMetadata projectMetadata )
570        throws MetadataRepositoryException
571    {
572
573        QueryResult<OrderedRows<String, String, String>> result = HFactory //
574            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
575            .setColumnFamily( cassandraArchivaManager.getProjectFamilyName() ) //
576            .setColumnNames( PROJECT_ID.toString() ) //
577            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
578            .addEqualsExpression( NAMESPACE_ID.toString(), projectMetadata.getNamespace() ) //
579            .addEqualsExpression( PROJECT_ID.toString(), projectMetadata.getId() ) //
580            .execute();
581
582        // project exists ? if yes return nothing to update here
583        if ( result.get().getCount() > 0 )
584        {
585            return;
586        }
587        else
588        {
589            Namespace namespace = updateOrAddNamespace( repositoryId, projectMetadata.getNamespace() );
590
591            String key =
592                new Project.KeyBuilder().withProjectId( projectMetadata.getId() ).withNamespace( namespace ).build();
593
594            String cf = cassandraArchivaManager.getProjectFamilyName();
595            projectTemplate.createMutator()
596                //  values
597                .addInsertion( key, cf, CassandraUtils.column( PROJECT_ID.toString(), projectMetadata.getId() ) ) //
598                .addInsertion( key, cf, CassandraUtils.column( REPOSITORY_NAME.toString(), repositoryId ) ) //
599                .addInsertion( key, cf, CassandraUtils.column( NAMESPACE_ID.toString(), projectMetadata.getNamespace() ) )//
600                .execute();
601        }
602    }
603
604    @Override
605    public Collection<String> getProjects( final String repoId, final String namespace )
606        throws MetadataResolutionException
607    {
608
609        QueryResult<OrderedRows<String, String, String>> result = HFactory //
610            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
611            .setColumnFamily( cassandraArchivaManager.getProjectFamilyName() ) //
612            .setColumnNames( PROJECT_ID.toString() ) //
613            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
614            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
615            .execute();
616
617        final Set<String> projects = new HashSet<String>( result.get().getCount() );
618
619        for ( Row<String, String, String> row : result.get() )
620        {
621            projects.add( getStringValue( row.getColumnSlice(), PROJECT_ID.toString() ) );
622        }
623
624        return projects;
625    }
626
627    @Override
628    public void removeProject( final String repositoryId, final String namespaceId, final String projectId )
629        throws MetadataRepositoryException
630    {
631
632        String key = new Project.KeyBuilder() //
633            .withProjectId( projectId ) //
634            .withNamespace( new Namespace( namespaceId, new Repository( repositoryId ) ) ) //
635            .build();
636
637        this.projectTemplate.deleteRow( key );
638
639        QueryResult<OrderedRows<String, String, String>> result = HFactory //
640            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
641            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
642            .setColumnNames( ID.toString() ) //
643            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
644            .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
645            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
646            .execute();
647
648        for ( Row<String, String, String> row : result.get() )
649        {
650            this.projectVersionMetadataTemplate.deleteRow( row.getKey() );
651            removeMailingList( row.getKey() );
652        }
653
654        result = HFactory //
655            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
656            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
657            .setColumnNames( PROJECT_ID.toString() ) //
658            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
659            .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
660            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
661            .execute();
662
663        for ( Row<String, String, String> row : result.get() )
664        {
665            this.artifactMetadataTemplate.deleteRow( row.getKey() );
666        }
667    }
668
669    @Override
670    public Collection<String> getProjectVersions( final String repoId, final String namespace, final String projectId )
671        throws MetadataResolutionException
672    {
673
674        QueryResult<OrderedRows<String, String, String>> result = HFactory //
675            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
676            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
677            .setColumnNames( PROJECT_VERSION.toString() ) //
678            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
679            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
680            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
681            .execute();
682
683        int count = result.get().getCount();
684
685        if ( count < 1 )
686        {
687            return Collections.emptyList();
688        }
689
690        Set<String> versions = new HashSet<String>( count );
691
692        for ( Row<String, String, String> orderedRows : result.get() )
693        {
694            versions.add( getStringValue( orderedRows.getColumnSlice(), PROJECT_VERSION.toString() ) );
695        }
696
697        return versions;
698
699    }
700
701    @Override
702    public ProjectMetadata getProject( final String repoId, final String namespace, final String id )
703        throws MetadataResolutionException
704    {
705
706        QueryResult<OrderedRows<String, String, String>> result = HFactory //
707            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
708            .setColumnFamily( cassandraArchivaManager.getProjectFamilyName() ) //
709            .setColumnNames( PROJECT_ID.toString() ) //
710            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
711            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
712            .addEqualsExpression( PROJECT_ID.toString(), id ) //
713            .execute();
714
715        int count = result.get().getCount();
716
717        if ( count < 1 )
718        {
719            return null;
720        }
721
722        ProjectMetadata projectMetadata = new ProjectMetadata();
723        projectMetadata.setId( id );
724        projectMetadata.setNamespace( namespace );
725
726        logger.debug( "getProject repoId: {}, namespace: {}, projectId: {} -> {}", repoId, namespace, id,
727                      projectMetadata );
728
729        return projectMetadata;
730    }
731
732    protected ProjectVersionMetadataModel mapProjectVersionMetadataModel( ColumnSlice<String, String> columnSlice )
733    {
734        ProjectVersionMetadataModel projectVersionMetadataModel = new ProjectVersionMetadataModel();
735        projectVersionMetadataModel.setId( getStringValue( columnSlice, ID.toString() ) );
736        projectVersionMetadataModel.setDescription( getStringValue( columnSlice, DESCRIPTION.toString() ) );
737        projectVersionMetadataModel.setName( getStringValue( columnSlice, NAME.toString() ) );
738        Namespace namespace = new Namespace( getStringValue( columnSlice, NAMESPACE_ID.toString() ), //
739                                             new Repository( getStringValue( columnSlice, REPOSITORY_NAME.toString() ) ) );
740        projectVersionMetadataModel.setNamespace( namespace );
741        projectVersionMetadataModel.setIncomplete(
742            Boolean.parseBoolean( getStringValue( columnSlice, "incomplete" ) ) );
743        projectVersionMetadataModel.setProjectId( getStringValue( columnSlice, PROJECT_ID.toString() ) );
744        projectVersionMetadataModel.setUrl( getStringValue( columnSlice, URL.toString() ) );
745        return projectVersionMetadataModel;
746    }
747
748
749    @Override
750    public void updateProjectVersion( String repositoryId, String namespaceId, String projectId,
751                                      ProjectVersionMetadata versionMetadata )
752        throws MetadataRepositoryException
753    {
754        try
755        {
756            Namespace namespace = getNamespace( repositoryId, namespaceId );
757
758            if ( namespace == null )
759            {
760                updateOrAddNamespace( repositoryId, namespaceId );
761            }
762
763            if ( getProject( repositoryId, namespaceId, projectId ) == null )
764            {
765                ProjectMetadata projectMetadata = new ProjectMetadata();
766                projectMetadata.setNamespace( namespaceId );
767                projectMetadata.setId( projectId );
768                updateProject( repositoryId, projectMetadata );
769            }
770
771        }
772        catch ( MetadataResolutionException e )
773        {
774            throw new MetadataRepositoryException( e.getMessage(), e );
775        }
776
777        QueryResult<OrderedRows<String, String, String>> result = HFactory //
778            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
779            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
780            .setColumnNames( PROJECT_VERSION.toString() ) //
781            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
782            .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
783            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
784            .addEqualsExpression( PROJECT_VERSION.toString(), versionMetadata.getId() ) //
785            .execute();
786
787        ProjectVersionMetadataModel projectVersionMetadataModel = null;
788        boolean creation = true;
789        if ( result.get().getCount() > 0 )
790        {
791            projectVersionMetadataModel =
792                mapProjectVersionMetadataModel( result.get().getList().get( 0 ).getColumnSlice() );
793            creation = false;
794        }
795        else
796        {
797            projectVersionMetadataModel = getModelMapper().map( versionMetadata, ProjectVersionMetadataModel.class );
798        }
799
800        projectVersionMetadataModel.setProjectId( projectId );
801        projectVersionMetadataModel.setNamespace( new Namespace( namespaceId, new Repository( repositoryId ) ) );
802
803        projectVersionMetadataModel.setCiManagement( versionMetadata.getCiManagement() );
804        projectVersionMetadataModel.setIssueManagement( versionMetadata.getIssueManagement() );
805        projectVersionMetadataModel.setOrganization( versionMetadata.getOrganization() );
806        projectVersionMetadataModel.setScm( versionMetadata.getScm() );
807
808        projectVersionMetadataModel.setMailingLists( versionMetadata.getMailingLists() );
809        projectVersionMetadataModel.setDependencies( versionMetadata.getDependencies() );
810        projectVersionMetadataModel.setLicenses( versionMetadata.getLicenses() );
811
812        // we don't test of repository and namespace really exist !
813        String key = new ProjectVersionMetadataModel.KeyBuilder() //
814            .withRepository( repositoryId ) //
815            .withNamespace( namespaceId ) //
816            .withProjectId( projectId ) //
817            .withProjectVersion( versionMetadata.getVersion() ) //
818            .withId( versionMetadata.getId() ) //
819            .build();
820
821        // FIXME nested objects to store!!!
822        if ( creation )
823        {
824            String cf = cassandraArchivaManager.getProjectVersionMetadataFamilyName();
825            Mutator<String> mutator = projectVersionMetadataTemplate.createMutator()
826                //  values
827                .addInsertion( key, cf, column( PROJECT_ID.toString(), projectId ) ) //
828                .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), repositoryId ) ) //
829                .addInsertion( key, cf, column( NAMESPACE_ID.toString(), namespaceId ) )//
830                .addInsertion( key, cf, column( PROJECT_VERSION.toString(), versionMetadata.getVersion() ) ); //
831
832            addInsertion( mutator, key, cf, DESCRIPTION.toString(), versionMetadata.getDescription() );
833
834            addInsertion( mutator, key, cf, NAME.toString(), versionMetadata.getName() );
835
836            addInsertion( mutator, key, cf, "incomplete", Boolean.toString( versionMetadata.isIncomplete() ) );
837
838            addInsertion( mutator, key, cf, URL.toString(), versionMetadata.getUrl() );
839            {
840                CiManagement ci = versionMetadata.getCiManagement();
841                if ( ci != null )
842                {
843                    addInsertion( mutator, key, cf, "ciManagement.system", ci.getSystem() );
844                    addInsertion( mutator, key, cf, "ciManagement.url", ci.getUrl() );
845                }
846            }
847
848            {
849                IssueManagement issueManagement = versionMetadata.getIssueManagement();
850
851                if ( issueManagement != null )
852                {
853                    addInsertion( mutator, key, cf, "issueManagement.system", issueManagement.getSystem() );
854                    addInsertion( mutator, key, cf, "issueManagement.url", issueManagement.getUrl() );
855                }
856            }
857
858            {
859                Organization organization = versionMetadata.getOrganization();
860                if ( organization != null )
861                {
862                    addInsertion( mutator, key, cf, "organization.name", organization.getName() );
863                    addInsertion( mutator, key, cf, "organization.url", organization.getUrl() );
864                }
865            }
866
867            {
868                Scm scm = versionMetadata.getScm();
869                if ( scm != null )
870                {
871                    addInsertion( mutator, key, cf, "scm.url", scm.getUrl() );
872                    addInsertion( mutator, key, cf, "scm.connection", scm.getConnection() );
873                    addInsertion( mutator, key, cf, "scm.developerConnection", scm.getDeveloperConnection() );
874                }
875            }
876
877            recordMailingList( key, versionMetadata.getMailingLists() );
878
879            recordLicenses( key, versionMetadata.getLicenses() );
880
881            recordDependencies( key, versionMetadata.getDependencies(), repositoryId );
882
883            MutationResult mutationResult = mutator.execute();
884        }
885        else
886        {
887            ColumnFamilyUpdater<String, String> updater = projectVersionMetadataTemplate.createUpdater( key );
888            addUpdateStringValue( updater, PROJECT_ID.toString(), projectId );
889            addUpdateStringValue( updater, REPOSITORY_NAME.toString(), repositoryId );
890            addUpdateStringValue( updater, NAMESPACE_ID.toString(), namespaceId );
891            addUpdateStringValue( updater, PROJECT_VERSION.toString(), versionMetadata.getVersion() );
892            addUpdateStringValue( updater, DESCRIPTION.toString(), versionMetadata.getDescription() );
893
894            addUpdateStringValue( updater, NAME.toString(), versionMetadata.getName() );
895
896            updater.setString( "incomplete", Boolean.toString( versionMetadata.isIncomplete() ) );
897            addUpdateStringValue( updater, URL.toString(), versionMetadata.getUrl() );
898
899            {
900                CiManagement ci = versionMetadata.getCiManagement();
901                if ( ci != null )
902                {
903                    addUpdateStringValue( updater, "ciManagement.system", ci.getSystem() );
904                    addUpdateStringValue( updater, "ciManagement.url", ci.getUrl() );
905                }
906            }
907            {
908                IssueManagement issueManagement = versionMetadata.getIssueManagement();
909                if ( issueManagement != null )
910                {
911                    addUpdateStringValue( updater, "issueManagement.system", issueManagement.getSystem() );
912                    addUpdateStringValue( updater, "issueManagement.url", issueManagement.getUrl() );
913                }
914            }
915            {
916                Organization organization = versionMetadata.getOrganization();
917                if ( organization != null )
918                {
919                    addUpdateStringValue( updater, "organization.name", organization.getName() );
920                    addUpdateStringValue( updater, "organization.url", organization.getUrl() );
921                }
922            }
923            {
924                Scm scm = versionMetadata.getScm();
925                if ( scm != null )
926                {
927                    addUpdateStringValue( updater, "scm.url", scm.getUrl() );
928                    addUpdateStringValue( updater, "scm.connection", scm.getConnection() );
929                    addUpdateStringValue( updater, "scm.developerConnection", scm.getDeveloperConnection() );
930                }
931            }
932
933            // update is a delete record
934            removeMailingList( key );
935            recordMailingList( key, versionMetadata.getMailingLists() );
936
937            removeLicenses( key );
938            recordLicenses( key, versionMetadata.getLicenses() );
939
940            removeDependencies( key );
941            recordDependencies( key, versionMetadata.getDependencies(), repositoryId );
942
943            projectVersionMetadataTemplate.update( updater );
944
945        }
946
947        ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
948        artifactMetadataModel.setRepositoryId( repositoryId );
949        artifactMetadataModel.setNamespace( namespaceId );
950        artifactMetadataModel.setProject( projectId );
951        artifactMetadataModel.setProjectVersion( versionMetadata.getVersion() );
952        artifactMetadataModel.setVersion( versionMetadata.getVersion() );
953        updateFacets( versionMetadata, artifactMetadataModel );
954
955    }
956
957
958    @Override
959    public ProjectVersionMetadata getProjectVersion( final String repoId, final String namespace,
960                                                     final String projectId, final String projectVersion )
961        throws MetadataResolutionException
962    {
963
964        QueryResult<OrderedRows<String, String, String>> result = HFactory //
965            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
966            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
967            .setColumnNames( PROJECT_VERSION.toString() ) //
968            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
969            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
970            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
971            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
972            .execute();
973
974        if ( result.get().getCount() < 1 )
975        {
976            return null;
977        }
978
979        String key = result.get().iterator().next().getKey();
980
981        ColumnFamilyResult<String, String> columnFamilyResult = this.projectVersionMetadataTemplate.queryColumns( key );
982
983        if ( !columnFamilyResult.hasResults() )
984        {
985            return null;
986        }
987
988        ProjectVersionMetadata projectVersionMetadata = new ProjectVersionMetadata();
989        projectVersionMetadata.setId( columnFamilyResult.getString( PROJECT_VERSION.toString() ) );
990        projectVersionMetadata.setDescription( columnFamilyResult.getString( DESCRIPTION.toString() ) );
991        projectVersionMetadata.setName( columnFamilyResult.getString( NAME.toString() ) );
992
993        projectVersionMetadata.setIncomplete( Boolean.parseBoolean( columnFamilyResult.getString( "incomplete" ) ) );
994
995        projectVersionMetadata.setUrl( columnFamilyResult.getString( URL.toString() ) );
996        {
997            String ciUrl = columnFamilyResult.getString( "ciManagement.url" );
998            String ciSystem = columnFamilyResult.getString( "ciManagement.system" );
999
1000            if ( StringUtils.isNotEmpty( ciSystem ) || StringUtils.isNotEmpty( ciUrl ) )
1001            {
1002                projectVersionMetadata.setCiManagement( new CiManagement( ciSystem, ciUrl ) );
1003            }
1004        }
1005        {
1006            String issueUrl = columnFamilyResult.getString( "issueManagement.url" );
1007            String issueSystem = columnFamilyResult.getString( "issueManagement.system" );
1008            if ( StringUtils.isNotEmpty( issueSystem ) || StringUtils.isNotEmpty( issueUrl ) )
1009            {
1010                projectVersionMetadata.setIssueManagement( new IssueManagement( issueSystem, issueUrl ) );
1011            }
1012        }
1013        {
1014            String organizationUrl = columnFamilyResult.getString( "organization.url" );
1015            String organizationName = columnFamilyResult.getString( "organization.name" );
1016            if ( StringUtils.isNotEmpty( organizationUrl ) || StringUtils.isNotEmpty( organizationName ) )
1017            {
1018                projectVersionMetadata.setOrganization( new Organization( organizationName, organizationUrl ) );
1019            }
1020        }
1021        {
1022            String devConn = columnFamilyResult.getString( "scm.developerConnection" );
1023            String conn = columnFamilyResult.getString( "scm.connection" );
1024            String url = columnFamilyResult.getString( "scm.url" );
1025            if ( StringUtils.isNotEmpty( devConn ) || StringUtils.isNotEmpty( conn ) || StringUtils.isNotEmpty( url ) )
1026            {
1027                projectVersionMetadata.setScm( new Scm( conn, devConn, url ) );
1028            }
1029        }
1030        projectVersionMetadata.setMailingLists( getMailingLists( key ) );
1031        projectVersionMetadata.setLicenses( getLicenses( key ) );
1032        projectVersionMetadata.setDependencies( getDependencies( key ) );
1033        // facets
1034
1035        result = HFactory //
1036            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1037            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1038            .setColumnNames( FACET_ID.toString(), KEY.toString(), VALUE.toString(), NAME.toString() ) //
1039            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
1040            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
1041            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
1042            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
1043            .execute();
1044
1045        Map<String, Map<String, String>> metadataFacetsPerFacetIds = new HashMap<>();
1046
1047        for ( Row<String, String, String> row : result.get() )
1048        {
1049            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
1050            String facetId = getStringValue( columnSlice, FACET_ID.toString() );
1051            Map<String, String> metaValues = metadataFacetsPerFacetIds.get( facetId );
1052            if ( metaValues == null )
1053            {
1054                metaValues = new HashMap<>();
1055                metadataFacetsPerFacetIds.put( facetId, metaValues );
1056            }
1057            metaValues.put( getStringValue( columnSlice, KEY.toString() ), getStringValue( columnSlice, VALUE.toString() ) );
1058        }
1059
1060        if ( !metadataFacetsPerFacetIds.isEmpty() )
1061        {
1062            for ( Map.Entry<String, Map<String, String>> entry : metadataFacetsPerFacetIds.entrySet() )
1063            {
1064                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
1065                if ( metadataFacetFactory != null )
1066                {
1067                    MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet();
1068                    metadataFacet.fromProperties( entry.getValue() );
1069                    projectVersionMetadata.addFacet( metadataFacet );
1070                }
1071            }
1072        }
1073
1074        return projectVersionMetadata;
1075    }
1076
1077    protected void recordMailingList( String projectVersionMetadataKey, List<MailingList> mailingLists )
1078    {
1079        if ( mailingLists == null || mailingLists.isEmpty() )
1080        {
1081            return;
1082        }
1083        Mutator<String> mailingMutator = this.mailingListTemplate.createMutator();
1084        for ( MailingList mailingList : mailingLists )
1085        {
1086            // we don't care about the key as the real used one with the projectVersionMetadata
1087            String keyMailingList = UUID.randomUUID().toString();
1088            String cfMailingList = cassandraArchivaManager.getMailingListFamilyName();
1089
1090            addInsertion( mailingMutator, keyMailingList, cfMailingList, "projectVersionMetadataModel.key",
1091                          projectVersionMetadataKey );
1092            addInsertion( mailingMutator, keyMailingList, cfMailingList, NAME.toString(), mailingList.getName() );
1093            addInsertion( mailingMutator, keyMailingList, cfMailingList, "mainArchiveUrl",
1094                          mailingList.getMainArchiveUrl() );
1095            addInsertion( mailingMutator, keyMailingList, cfMailingList, "postAddress", mailingList.getPostAddress() );
1096            addInsertion( mailingMutator, keyMailingList, cfMailingList, "subscribeAddress",
1097                          mailingList.getSubscribeAddress() );
1098            addInsertion( mailingMutator, keyMailingList, cfMailingList, "unsubscribeAddress",
1099                          mailingList.getUnsubscribeAddress() );
1100            int idx = 0;
1101            for ( String otherArchive : mailingList.getOtherArchives() )
1102            {
1103                addInsertion( mailingMutator, keyMailingList, cfMailingList, "otherArchive." + idx, otherArchive );
1104                idx++;
1105            }
1106
1107        }
1108        mailingMutator.execute();
1109    }
1110
1111    protected void removeMailingList( String projectVersionMetadataKey )
1112    {
1113
1114        QueryResult<OrderedRows<String, String, String>> result =
1115            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1116                .setColumnFamily( cassandraArchivaManager.getMailingListFamilyName() ) //
1117                .setColumnNames( NAME.toString() ) //
1118                .setRowCount( Integer.MAX_VALUE ) //
1119                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1120                .execute();
1121
1122        if ( result.get().getCount() < 1 )
1123        {
1124            return;
1125        }
1126
1127        for ( Row<String, String, String> row : result.get() )
1128        {
1129            this.mailingListTemplate.deleteRow( row.getKey() );
1130        }
1131
1132    }
1133
1134    protected List<MailingList> getMailingLists( String projectVersionMetadataKey )
1135    {
1136        List<MailingList> mailingLists = new ArrayList<>();
1137
1138        QueryResult<OrderedRows<String, String, String>> result =
1139            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1140                .setColumnFamily( cassandraArchivaManager.getMailingListFamilyName() ) //
1141                .setColumnNames( NAME.toString() ) //
1142                .setRowCount( Integer.MAX_VALUE ) //
1143                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1144                .execute();
1145        for ( Row<String, String, String> row : result.get() )
1146        {
1147            ColumnFamilyResult<String, String> columnFamilyResult =
1148                this.mailingListTemplate.queryColumns( row.getKey() );
1149
1150            MailingList mailingList = new MailingList();
1151            mailingList.setName( columnFamilyResult.getString( NAME.toString() ) );
1152            mailingList.setMainArchiveUrl( columnFamilyResult.getString( "mainArchiveUrl" ) );
1153            mailingList.setPostAddress( columnFamilyResult.getString( "postAddress" ) );
1154            mailingList.setSubscribeAddress( columnFamilyResult.getString( "subscribeAddress" ) );
1155            mailingList.setUnsubscribeAddress( columnFamilyResult.getString( "unsubscribeAddress" ) );
1156
1157            List<String> otherArchives = new ArrayList<>();
1158
1159            for ( String columnName : columnFamilyResult.getColumnNames() )
1160            {
1161                if ( StringUtils.startsWith( columnName, "otherArchive." ) )
1162                {
1163                    otherArchives.add( columnFamilyResult.getString( columnName ) );
1164                }
1165            }
1166
1167            mailingList.setOtherArchives( otherArchives );
1168            mailingLists.add( mailingList );
1169        }
1170
1171        return mailingLists;
1172    }
1173
1174    protected void recordLicenses( String projectVersionMetadataKey, List<License> licenses )
1175    {
1176
1177        if ( licenses == null || licenses.isEmpty() )
1178        {
1179            return;
1180        }
1181        Mutator<String> licenseMutator = this.licenseTemplate.createMutator();
1182
1183        for ( License license : licenses )
1184        {
1185            // we don't care about the key as the real used one with the projectVersionMetadata
1186            String keyLicense = UUID.randomUUID().toString();
1187            String cfLicense = cassandraArchivaManager.getLicenseFamilyName();
1188
1189            addInsertion( licenseMutator, keyLicense, cfLicense, "projectVersionMetadataModel.key",
1190                          projectVersionMetadataKey );
1191
1192            addInsertion( licenseMutator, keyLicense, cfLicense, NAME.toString(), license.getName() );
1193
1194            addInsertion( licenseMutator, keyLicense, cfLicense, URL.toString(), license.getUrl() );
1195
1196        }
1197        licenseMutator.execute();
1198    }
1199
1200    protected void removeLicenses( String projectVersionMetadataKey )
1201    {
1202
1203        QueryResult<OrderedRows<String, String, String>> result =
1204            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1205                .setColumnFamily( cassandraArchivaManager.getLicenseFamilyName() ) //
1206                .setColumnNames( NAME.toString() ) //
1207                .setRowCount( Integer.MAX_VALUE ) //
1208                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1209                .execute();
1210        for ( Row<String, String, String> row : result.get() )
1211        {
1212            this.licenseTemplate.deleteRow( row.getKey() );
1213        }
1214    }
1215
1216    protected List<License> getLicenses( String projectVersionMetadataKey )
1217    {
1218        List<License> licenses = new ArrayList<>();
1219
1220        QueryResult<OrderedRows<String, String, String>> result =
1221            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1222                .setColumnFamily( cassandraArchivaManager.getLicenseFamilyName() ) //
1223                .setColumnNames( "projectVersionMetadataModel.key" ) //
1224                .setRowCount( Integer.MAX_VALUE ) //
1225                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1226                .execute();
1227
1228        for ( Row<String, String, String> row : result.get() )
1229        {
1230            ColumnFamilyResult<String, String> columnFamilyResult = this.licenseTemplate.queryColumns( row.getKey() );
1231
1232            licenses.add(
1233                new License( columnFamilyResult.getString( NAME.toString() ), columnFamilyResult.getString( URL.toString() ) ) );
1234        }
1235
1236        return licenses;
1237    }
1238
1239
1240    protected void recordDependencies( String projectVersionMetadataKey, List<Dependency> dependencies,
1241                                       String repositoryId )
1242    {
1243
1244        if ( dependencies == null || dependencies.isEmpty() )
1245        {
1246            return;
1247        }
1248        Mutator<String> dependencyMutator = this.dependencyTemplate.createMutator();
1249
1250        for ( Dependency dependency : dependencies )
1251        {
1252            // we don't care about the key as the real used one with the projectVersionMetadata
1253            String keyDependency = UUID.randomUUID().toString();
1254            String cfDependency = cassandraArchivaManager.getDependencyFamilyName();
1255
1256            addInsertion( dependencyMutator, keyDependency, cfDependency, "projectVersionMetadataModel.key",
1257                          projectVersionMetadataKey );
1258
1259            addInsertion( dependencyMutator, keyDependency, cfDependency, REPOSITORY_NAME.toString(), repositoryId );
1260
1261            addInsertion( dependencyMutator, keyDependency, cfDependency, "classifier", dependency.getClassifier() );
1262
1263            addInsertion( dependencyMutator, keyDependency, cfDependency, "optional",
1264                          Boolean.toString( dependency.isOptional() ) );
1265
1266            addInsertion( dependencyMutator, keyDependency, cfDependency, "scope", dependency.getScope() );
1267
1268            addInsertion( dependencyMutator, keyDependency, cfDependency, "systemPath", dependency.getSystemPath() );
1269
1270            addInsertion( dependencyMutator, keyDependency, cfDependency, "type", dependency.getType() );
1271
1272            addInsertion( dependencyMutator, keyDependency, cfDependency, ARTIFACT_ID.toString(), dependency.getArtifactId() );
1273
1274            addInsertion( dependencyMutator, keyDependency, cfDependency, GROUP_ID.toString(), dependency.getGroupId() );
1275
1276            addInsertion( dependencyMutator, keyDependency, cfDependency, VERSION.toString(), dependency.getVersion() );
1277
1278        }
1279        dependencyMutator.execute();
1280    }
1281
1282    protected void removeDependencies( String projectVersionMetadataKey )
1283    {
1284
1285        QueryResult<OrderedRows<String, String, String>> result =
1286            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1287                .setColumnFamily( cassandraArchivaManager.getDependencyFamilyName() ) //
1288                .setColumnNames( GROUP_ID.toString() ) //
1289                .setRowCount( Integer.MAX_VALUE ) //
1290                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1291                .execute();
1292        for ( Row<String, String, String> row : result.get() )
1293        {
1294            this.dependencyTemplate.deleteRow( row.getKey() );
1295        }
1296    }
1297
1298    protected List<Dependency> getDependencies( String projectVersionMetadataKey )
1299    {
1300        List<Dependency> dependencies = new ArrayList<>();
1301
1302        QueryResult<OrderedRows<String, String, String>> result =
1303            HFactory.createRangeSlicesQuery( cassandraArchivaManager.getKeyspace(), ss, ss, ss ) //
1304                .setColumnFamily( cassandraArchivaManager.getDependencyFamilyName() ) //
1305                .setColumnNames( "projectVersionMetadataModel.key" ) //
1306                .setRowCount( Integer.MAX_VALUE ) //
1307                .addEqualsExpression( "projectVersionMetadataModel.key", projectVersionMetadataKey ) //
1308                .execute();
1309
1310        for ( Row<String, String, String> row : result.get() )
1311        {
1312            ColumnFamilyResult<String, String> columnFamilyResult =
1313                this.dependencyTemplate.queryColumns( row.getKey() );
1314
1315            Dependency dependency = new Dependency();
1316            dependency.setClassifier( columnFamilyResult.getString( "classifier" ) );
1317
1318            dependency.setOptional( Boolean.parseBoolean( columnFamilyResult.getString( "optional" ) ) );
1319
1320            dependency.setScope( columnFamilyResult.getString( "scope" ) );
1321
1322            dependency.setSystemPath( columnFamilyResult.getString( "systemPath" ) );
1323
1324            dependency.setType( columnFamilyResult.getString( "type" ) );
1325
1326            dependency.setArtifactId( columnFamilyResult.getString( ARTIFACT_ID.toString() ) );
1327
1328            dependency.setGroupId( columnFamilyResult.getString( GROUP_ID.toString() ) );
1329
1330            dependency.setVersion( columnFamilyResult.getString( VERSION.toString() ) );
1331
1332            dependencies.add( dependency );
1333        }
1334
1335        return dependencies;
1336    }
1337
1338    @Override
1339    public void updateArtifact( String repositoryId, String namespaceId, String projectId, String projectVersion,
1340                                ArtifactMetadata artifactMeta )
1341        throws MetadataRepositoryException
1342    {
1343
1344        Namespace namespace = getNamespace( repositoryId, namespaceId );
1345        if ( namespace == null )
1346        {
1347            namespace = updateOrAddNamespace( repositoryId, namespaceId );
1348        }
1349
1350        ProjectMetadata projectMetadata = new ProjectMetadata();
1351        projectMetadata.setId( projectId );
1352        projectMetadata.setNamespace( namespaceId );
1353        updateProject( repositoryId, projectMetadata );
1354
1355        String key = new ArtifactMetadataModel.KeyBuilder().withNamespace( namespace ).withProject( projectId ).withId(
1356            artifactMeta.getId() ).withProjectVersion( projectVersion ).build();
1357
1358        // exists?
1359
1360        boolean exists = this.artifactMetadataTemplate.isColumnsExist( key );
1361
1362        if ( exists )
1363        {
1364            // updater
1365            ColumnFamilyUpdater<String, String> updater = this.artifactMetadataTemplate.createUpdater( key );
1366            updater.setLong( FILE_LAST_MODIFIED.toString(), artifactMeta.getFileLastModified().getTime() );
1367            updater.setLong( WHEN_GATHERED.toString(), artifactMeta.getWhenGathered().getTime() );
1368            updater.setLong( SIZE.toString(), artifactMeta.getSize() );
1369            addUpdateStringValue( updater, MD5.toString(), artifactMeta.getMd5() );
1370            addUpdateStringValue( updater, SHA1.toString(), artifactMeta.getSha1() );
1371            addUpdateStringValue( updater, VERSION.toString(), artifactMeta.getVersion() );
1372            this.artifactMetadataTemplate.update( updater );
1373        }
1374        else
1375        {
1376            String cf = this.cassandraArchivaManager.getArtifactMetadataFamilyName();
1377            // create
1378            this.artifactMetadataTemplate.createMutator() //
1379                .addInsertion( key, cf, column( ID.toString(), artifactMeta.getId() ) )//
1380                .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), repositoryId ) ) //
1381                .addInsertion( key, cf, column( NAMESPACE_ID.toString(), namespaceId ) ) //
1382                .addInsertion( key, cf, column( PROJECT.toString(), artifactMeta.getProject() ) ) //
1383                .addInsertion( key, cf, column( PROJECT_VERSION.toString(), projectVersion ) ) //
1384                .addInsertion( key, cf, column( VERSION.toString(), artifactMeta.getVersion() ) ) //
1385                .addInsertion( key, cf, column( FILE_LAST_MODIFIED.toString(), artifactMeta.getFileLastModified().getTime() ) ) //
1386                .addInsertion( key, cf, column( SIZE.toString(), artifactMeta.getSize() ) ) //
1387                .addInsertion( key, cf, column( MD5.toString(), artifactMeta.getMd5() ) ) //
1388                .addInsertion( key, cf, column( SHA1.toString(), artifactMeta.getSha1() ) ) //
1389                .addInsertion( key, cf, column( WHEN_GATHERED.toString(), artifactMeta.getWhenGathered().getTime() ) )//
1390                .execute();
1391        }
1392
1393        key = new ProjectVersionMetadataModel.KeyBuilder() //
1394            .withRepository( repositoryId ) //
1395            .withNamespace( namespace ) //
1396            .withProjectId( projectId ) //
1397            .withProjectVersion( projectVersion ) //
1398            .withId( artifactMeta.getId() ) //
1399            .build();
1400
1401        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1402            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1403            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
1404            .setColumnNames( VERSION.toString() ) //
1405            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1406            .addEqualsExpression( NAMESPACE_ID.toString(), namespaceId ) //
1407            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
1408            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
1409            .addEqualsExpression( VERSION.toString(), artifactMeta.getVersion() ) //
1410            .execute();
1411
1412        exists = result.get().getCount() > 0;
1413
1414        if ( !exists )
1415        {
1416            String cf = this.cassandraArchivaManager.getProjectVersionMetadataFamilyName();
1417
1418            projectVersionMetadataTemplate.createMutator() //
1419                .addInsertion( key, cf, column( NAMESPACE_ID.toString(), namespace.getName() ) ) //
1420                .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), repositoryId ) ) //
1421                .addInsertion( key, cf, column( PROJECT_VERSION.toString(), projectVersion ) ) //
1422                .addInsertion( key, cf, column( PROJECT_ID.toString(), projectId ) ) //
1423                .addInsertion( key, cf, column( VERSION.toString(), artifactMeta.getVersion() ) ) //
1424                .execute();
1425
1426        }
1427
1428        ArtifactMetadataModel artifactMetadataModel = new ArtifactMetadataModel();
1429
1430        artifactMetadataModel.setRepositoryId( repositoryId );
1431        artifactMetadataModel.setNamespace( namespaceId );
1432        artifactMetadataModel.setProject( projectId );
1433        artifactMetadataModel.setProjectVersion( projectVersion );
1434        artifactMetadataModel.setVersion( artifactMeta.getVersion() );
1435        artifactMetadataModel.setFileLastModified( artifactMeta.getFileLastModified() == null
1436                                                       ? new Date().getTime()
1437                                                       : artifactMeta.getFileLastModified().getTime() );
1438
1439        // now facets
1440        updateFacets( artifactMeta, artifactMetadataModel );
1441
1442    }
1443
1444    @Override
1445    public Collection<String> getArtifactVersions( final String repoId, final String namespace, final String projectId,
1446                                                   final String projectVersion )
1447        throws MetadataResolutionException
1448    {
1449
1450        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1451            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1452            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
1453            .setColumnNames( VERSION.toString() ) //
1454            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
1455            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
1456            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
1457            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
1458            .execute();
1459
1460        final Set<String> versions = new HashSet<String>();
1461
1462        for ( Row<String, String, String> row : result.get() )
1463        {
1464            versions.add( getStringValue( row.getColumnSlice(), VERSION.toString() ) );
1465        }
1466
1467        return versions;
1468
1469    }
1470
1471    /**
1472     * iterate over available facets to remove/add from the artifactMetadata
1473     *
1474     * @param facetedMetadata
1475     * @param artifactMetadataModel only use for the key
1476     */
1477    private void updateFacets( final FacetedMetadata facetedMetadata,
1478                               final ArtifactMetadataModel artifactMetadataModel )
1479    {
1480
1481        String cf = cassandraArchivaManager.getMetadataFacetFamilyName();
1482
1483        for ( final String facetId : metadataFacetFactories.keySet() )
1484        {
1485            MetadataFacet metadataFacet = facetedMetadata.getFacet( facetId );
1486            if ( metadataFacet == null )
1487            {
1488                continue;
1489            }
1490            // clean first
1491
1492            QueryResult<OrderedRows<String, String, String>> result =
1493                HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1494                    .setColumnFamily( cf ) //
1495                    .setColumnNames( REPOSITORY_NAME.toString() ) //
1496                    .addEqualsExpression( REPOSITORY_NAME.toString(), artifactMetadataModel.getRepositoryId() ) //
1497                    .addEqualsExpression( NAMESPACE_ID.toString(), artifactMetadataModel.getNamespace() ) //
1498                    .addEqualsExpression( PROJECT_ID.toString(), artifactMetadataModel.getProject() ) //
1499                    .addEqualsExpression( PROJECT_VERSION.toString(), artifactMetadataModel.getProjectVersion() ) //
1500                    .addEqualsExpression( FACET_ID.toString(), facetId ) //
1501                    .execute();
1502
1503            for ( Row<String, String, String> row : result.get().getList() )
1504            {
1505                this.metadataFacetTemplate.deleteRow( row.getKey() );
1506            }
1507
1508            Map<String, String> properties = metadataFacet.toProperties();
1509
1510            for ( Map.Entry<String, String> entry : properties.entrySet() )
1511            {
1512                String key = new MetadataFacetModel.KeyBuilder().withKey( entry.getKey() ).withArtifactMetadataModel(
1513                    artifactMetadataModel ).withFacetId( facetId ).withName( metadataFacet.getName() ).build();
1514                Mutator<String> mutator = metadataFacetTemplate.createMutator() //
1515                    .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), artifactMetadataModel.getRepositoryId() ) ) //
1516                    .addInsertion( key, cf, column( NAMESPACE_ID.toString(), artifactMetadataModel.getNamespace() ) ) //
1517                    .addInsertion( key, cf, column( PROJECT_ID.toString(), artifactMetadataModel.getProject() ) ) //
1518                    .addInsertion( key, cf, column( PROJECT_VERSION.toString(), artifactMetadataModel.getProjectVersion() ) ) //
1519                    .addInsertion( key, cf, column( FACET_ID.toString(), facetId ) ) //
1520                    .addInsertion( key, cf, column( KEY.toString(), entry.getKey() ) ) //
1521                    .addInsertion( key, cf, column( VALUE.toString(), entry.getValue() ) );
1522
1523                if ( metadataFacet.getName() != null )
1524                {
1525                    mutator.addInsertion( key, cf, column( NAME.toString(), metadataFacet.getName() ) );
1526                }
1527
1528                mutator.execute();
1529            }
1530        }
1531    }
1532
1533
1534    @Override
1535    public List<String> getMetadataFacets( final String repositoryId, final String facetId )
1536        throws MetadataRepositoryException
1537    {
1538
1539        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1540            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1541            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1542            .setColumnNames( NAME.toString() ) //
1543            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1544            .addEqualsExpression( FACET_ID.toString(), facetId ) //
1545            .execute();
1546
1547        final List<String> facets = new ArrayList<>();
1548
1549        for ( Row<String, String, String> row : result.get() )
1550        {
1551            facets.add( getStringValue( row.getColumnSlice(), NAME.toString() ) );
1552        }
1553        return facets;
1554    }
1555
1556    @Override
1557    public boolean hasMetadataFacet( String repositoryId, String facetId )
1558        throws MetadataRepositoryException
1559    {
1560        return !getMetadataFacets( repositoryId, facetId ).isEmpty();
1561    }
1562
1563    @Override
1564    public MetadataFacet getMetadataFacet( final String repositoryId, final String facetId, final String name )
1565        throws MetadataRepositoryException
1566    {
1567
1568        MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( facetId );
1569        if ( metadataFacetFactory == null )
1570        {
1571            return null;
1572        }
1573
1574        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1575            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1576            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1577            .setColumnNames( KEY.toString(), VALUE.toString() ) //
1578            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1579            .addEqualsExpression( FACET_ID.toString(), facetId ) //
1580            .addEqualsExpression( NAME.toString(), name ) //
1581            .execute();
1582
1583        MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet( repositoryId, name );
1584        int size = result.get().getCount();
1585        if ( size < 1 )
1586        {
1587            return null;
1588        }
1589        Map<String, String> map = new HashMap<>( size );
1590        for ( Row<String, String, String> row : result.get() )
1591        {
1592            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
1593            map.put( getStringValue( columnSlice, KEY.toString() ), getStringValue( columnSlice, VALUE.toString() ) );
1594        }
1595        metadataFacet.fromProperties( map );
1596        return metadataFacet;
1597    }
1598
1599    @Override
1600    public void addMetadataFacet( String repositoryId, MetadataFacet metadataFacet )
1601        throws MetadataRepositoryException
1602    {
1603
1604        if ( metadataFacet == null )
1605        {
1606            return;
1607        }
1608
1609        if ( metadataFacet.toProperties().isEmpty() )
1610        {
1611            String key = new MetadataFacetModel.KeyBuilder().withRepositoryId( repositoryId ).withFacetId(
1612                metadataFacet.getFacetId() ).withName( metadataFacet.getName() ).build();
1613
1614            boolean exists = this.metadataFacetTemplate.isColumnsExist( key );
1615
1616            if ( exists )
1617            {
1618                ColumnFamilyUpdater<String, String> updater = this.metadataFacetTemplate.createUpdater( key );
1619                addUpdateStringValue( updater, FACET_ID.toString(), metadataFacet.getFacetId() );
1620                addUpdateStringValue( updater, NAME.toString(), metadataFacet.getName() );
1621                this.metadataFacetTemplate.update( updater );
1622            }
1623            else
1624            {
1625                String cf = this.cassandraArchivaManager.getMetadataFacetFamilyName();
1626                this.metadataFacetTemplate.createMutator() //
1627                    .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), repositoryId ) ) //
1628                    .addInsertion( key, cf, column( FACET_ID.toString(), metadataFacet.getFacetId() ) ) //
1629                    .addInsertion( key, cf, column( NAME.toString(), metadataFacet.getName() ) ) //
1630                    .execute();
1631            }
1632
1633        }
1634        else
1635        {
1636            for ( Map.Entry<String, String> entry : metadataFacet.toProperties().entrySet() )
1637            {
1638                String key = new MetadataFacetModel.KeyBuilder().withRepositoryId( repositoryId ).withFacetId(
1639                    metadataFacet.getFacetId() ).withName( metadataFacet.getName() ).withKey( entry.getKey() ).build();
1640
1641                boolean exists = this.metadataFacetTemplate.isColumnsExist( key );
1642                if ( !exists )
1643                {
1644                    String cf = this.cassandraArchivaManager.getMetadataFacetFamilyName();
1645                    this.metadataFacetTemplate.createMutator() //
1646                        .addInsertion( key, cf, column( REPOSITORY_NAME.toString(), repositoryId ) ) //
1647                        .addInsertion( key, cf, column( FACET_ID.toString(), metadataFacet.getFacetId() ) ) //
1648                        .addInsertion( key, cf, column( NAME.toString(), metadataFacet.getName() ) ) //
1649                        .addInsertion( key, cf, column( KEY.toString(), entry.getKey() ) ) //
1650                        .addInsertion( key, cf, column( VALUE.toString(), entry.getValue() ) ) //
1651                        .execute();
1652                }
1653                else
1654                {
1655                    ColumnFamilyUpdater<String, String> updater = this.metadataFacetTemplate.createUpdater( key );
1656                    addUpdateStringValue( updater, VALUE.toString(), entry.getValue() );
1657                    this.metadataFacetTemplate.update( updater );
1658                }
1659            }
1660        }
1661    }
1662
1663    @Override
1664    public void removeMetadataFacets( final String repositoryId, final String facetId )
1665        throws MetadataRepositoryException
1666    {
1667
1668        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1669            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1670            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1671            .setColumnNames( KEY.toString(), VALUE.toString() ) //
1672            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1673            .addEqualsExpression( FACET_ID.toString(), facetId ) //
1674            .execute();
1675
1676        for ( Row<String, String, String> row : result.get() )
1677        {
1678            this.metadataFacetTemplate.deleteRow( row.getKey() );
1679        }
1680
1681    }
1682
1683    @Override
1684    public void removeMetadataFacet( final String repositoryId, final String facetId, final String name )
1685        throws MetadataRepositoryException
1686    {
1687
1688        QueryResult<OrderedRows<String, String, String>> result = HFactory //
1689            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1690            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1691            .setColumnNames( KEY.toString(), VALUE.toString() ) //
1692            .addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1693            .addEqualsExpression( FACET_ID.toString(), facetId ) //
1694            .addEqualsExpression( NAME.toString(), name ) //
1695            .execute();
1696
1697        for ( Row<String, String, String> row : result.get() )
1698        {
1699            this.metadataFacetTemplate.deleteRow( row.getKey() );
1700        }
1701    }
1702
1703    @Override
1704    public List<ArtifactMetadata> getArtifactsByDateRange( final String repositoryId, final Date startTime,
1705                                                           final Date endTime )
1706        throws MetadataRepositoryException
1707    {
1708
1709        LongSerializer ls = LongSerializer.get();
1710        RangeSlicesQuery<String, String, Long> query = HFactory //
1711            .createRangeSlicesQuery( keyspace, ss, ss, ls ) //
1712            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
1713            .setColumnNames( ArtifactMetadataModel.COLUMNS ); //
1714
1715        if ( startTime != null )
1716        {
1717            query = query.addGteExpression( WHEN_GATHERED.toString(), startTime.getTime() );
1718        }
1719        if ( endTime != null )
1720        {
1721            query = query.addLteExpression( WHEN_GATHERED.toString(), endTime.getTime() );
1722        }
1723        QueryResult<OrderedRows<String, String, Long>> result = query.execute();
1724
1725        List<ArtifactMetadata> artifactMetadatas = new ArrayList<>( result.get().getCount() );
1726
1727        for ( Row<String, String, Long> row : result.get() )
1728        {
1729            ColumnSlice<String, Long> columnSlice = row.getColumnSlice();
1730            String repositoryName = getAsStringValue( columnSlice, REPOSITORY_NAME.toString() );
1731            if ( StringUtils.equals( repositoryName, repositoryId ) )
1732            {
1733
1734                artifactMetadatas.add( mapArtifactMetadataLongColumnSlice( columnSlice ) );
1735            }
1736        }
1737
1738        return artifactMetadatas;
1739    }
1740
1741
1742    protected ArtifactMetadata mapArtifactMetadataLongColumnSlice( ColumnSlice<String, Long> columnSlice )
1743    {
1744        ArtifactMetadata artifactMetadata = new ArtifactMetadata();
1745        artifactMetadata.setNamespace( getAsStringValue( columnSlice, NAMESPACE_ID.toString() ) );
1746        artifactMetadata.setSize( getLongValue( columnSlice, SIZE.toString() ) );
1747        artifactMetadata.setId( getAsStringValue( columnSlice, ID.toString() ) );
1748        artifactMetadata.setFileLastModified( getLongValue( columnSlice, FILE_LAST_MODIFIED.toString() ) );
1749        artifactMetadata.setMd5( getAsStringValue( columnSlice, MD5.toString() ) );
1750        artifactMetadata.setProject( getAsStringValue( columnSlice, PROJECT.toString() ) );
1751        artifactMetadata.setProjectVersion( getAsStringValue( columnSlice, PROJECT_VERSION.toString() ) );
1752        artifactMetadata.setRepositoryId( getAsStringValue( columnSlice, REPOSITORY_NAME.toString() ) );
1753        artifactMetadata.setSha1( getAsStringValue( columnSlice, SHA1.toString() ) );
1754        artifactMetadata.setVersion( getAsStringValue( columnSlice, VERSION.toString() ) );
1755        Long whenGathered = getLongValue( columnSlice, WHEN_GATHERED.toString() );
1756        if ( whenGathered != null )
1757        {
1758            artifactMetadata.setWhenGathered( new Date( whenGathered ) );
1759        }
1760        return artifactMetadata;
1761    }
1762
1763    protected ArtifactMetadata mapArtifactMetadataStringColumnSlice( ColumnSlice<String, String> columnSlice )
1764    {
1765        ArtifactMetadata artifactMetadata = new ArtifactMetadata();
1766        artifactMetadata.setNamespace( getStringValue( columnSlice, NAMESPACE_ID.toString() ) );
1767        artifactMetadata.setSize( getAsLongValue( columnSlice, SIZE.toString() ) );
1768        artifactMetadata.setId( getStringValue( columnSlice, ID.toString() ) );
1769        artifactMetadata.setFileLastModified( getAsLongValue( columnSlice, FILE_LAST_MODIFIED.toString() ) );
1770        artifactMetadata.setMd5( getStringValue( columnSlice, MD5.toString() ) );
1771        artifactMetadata.setProject( getStringValue( columnSlice, PROJECT.toString() ) );
1772        artifactMetadata.setProjectVersion( getStringValue( columnSlice, PROJECT_VERSION.toString() ) );
1773        artifactMetadata.setRepositoryId( getStringValue( columnSlice, REPOSITORY_NAME.toString() ) );
1774        artifactMetadata.setSha1( getStringValue( columnSlice, SHA1.toString() ) );
1775        artifactMetadata.setVersion( getStringValue( columnSlice, VERSION.toString() ) );
1776        Long whenGathered = getAsLongValue( columnSlice, WHEN_GATHERED.toString() );
1777        if ( whenGathered != null )
1778        {
1779            artifactMetadata.setWhenGathered( new Date( whenGathered ) );
1780        }
1781        return artifactMetadata;
1782    }
1783
1784    @Override
1785    public Collection<ArtifactMetadata> getArtifactsByChecksum( final String repositoryId, final String checksum )
1786        throws MetadataRepositoryException
1787    {
1788
1789        // cql cannot run or in queries so running twice the query
1790        Map<String, ArtifactMetadata> artifactMetadataMap = new HashMap<>();
1791
1792        RangeSlicesQuery<String, String, String> query = HFactory //
1793            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1794            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
1795            .setColumnNames( ArtifactMetadataModel.COLUMNS ); //
1796
1797        query = query.addEqualsExpression( SHA1.toString(), checksum ).addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId );
1798
1799        QueryResult<OrderedRows<String, String, String>> result = query.execute();
1800
1801        for ( Row<String, String, String> row : result.get() )
1802        {
1803            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
1804
1805            artifactMetadataMap.put( row.getKey(), mapArtifactMetadataStringColumnSlice( columnSlice ) );
1806
1807        }
1808
1809        query = HFactory //
1810            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1811            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
1812            .setColumnNames( NAMESPACE_ID.toString(), SIZE.toString(), ID.toString(), FILE_LAST_MODIFIED.toString(), MD5.toString(), PROJECT.toString(), PROJECT_VERSION.toString(),
1813                             REPOSITORY_NAME.toString(), VERSION.toString(), WHEN_GATHERED.toString(), SHA1.toString() ); //
1814
1815        query = query.addEqualsExpression( MD5.toString(), checksum ).addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId );
1816
1817        result = query.execute();
1818
1819        for ( Row<String, String, String> row : result.get() )
1820        {
1821            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
1822
1823            artifactMetadataMap.put( row.getKey(), mapArtifactMetadataStringColumnSlice( columnSlice ) );
1824
1825        }
1826
1827        return artifactMetadataMap.values();
1828    }
1829
1830    /**
1831     * Project version and artifact level metadata are stored in the same place, no distinctions in Cassandra
1832     * implementation, just calls {@link #getArtifactsByMetadata(String, String, String)}
1833     */
1834    @Override
1835    public List<ArtifactMetadata> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
1836        throws MetadataRepositoryException
1837    {
1838        return getArtifactsByMetadata( key, value, repositoryId );
1839    }
1840
1841    @Override
1842    public List<ArtifactMetadata> getArtifactsByMetadata( String key, String value, String repositoryId )
1843        throws MetadataRepositoryException
1844    {
1845        RangeSlicesQuery<String, String, String> query =
1846            HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1847            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
1848            .setColumnNames( MetadataFacetModel.COLUMNS ) //
1849            .addEqualsExpression( VALUE.toString(), value );
1850
1851        if ( key != null )
1852        {
1853            query.addEqualsExpression( KEY.toString(), key ); //
1854        }
1855        if ( repositoryId != null )
1856        {
1857            query.addEqualsExpression( "repositoryName", repositoryId );
1858        }
1859
1860        QueryResult<OrderedRows<String, String, String>> metadataFacetResult = query.execute();
1861        if ( metadataFacetResult.get() == null || metadataFacetResult.get().getCount() < 1 )
1862        {
1863            return Collections.emptyList();
1864        }
1865
1866        List<ArtifactMetadata> artifactMetadatas = new LinkedList<ArtifactMetadata>();
1867
1868        // TODO doing multiple queries, there should be a way to get all the artifactMetadatas for any number of
1869        // projects
1870        for ( Row<String, String, String> row : metadataFacetResult.get() )
1871        {
1872            QueryResult<OrderedRows<String, String, String>> artifactMetadataResult =
1873                HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1874                .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
1875                .setColumnNames( ArtifactMetadataModel.COLUMNS ) //
1876                .setRowCount( Integer.MAX_VALUE ) //
1877                .addEqualsExpression( REPOSITORY_NAME.toString(),
1878                                      getStringValue( row.getColumnSlice(), REPOSITORY_NAME ) ) //
1879                .addEqualsExpression( NAMESPACE_ID.toString(), getStringValue( row.getColumnSlice(), NAMESPACE_ID ) ) //
1880                .addEqualsExpression( PROJECT.toString(), getStringValue( row.getColumnSlice(), PROJECT_ID ) ) //
1881                .addEqualsExpression( PROJECT_VERSION.toString(),
1882                                      getStringValue( row.getColumnSlice(), PROJECT_VERSION ) ) //
1883                .execute();
1884
1885            if ( artifactMetadataResult.get() == null || artifactMetadataResult.get().getCount() < 1 )
1886            {
1887                return Collections.emptyList();
1888            }
1889
1890            for ( Row<String, String, String> artifactMetadataRow : artifactMetadataResult.get() )
1891            {
1892                artifactMetadatas.add( mapArtifactMetadataStringColumnSlice( artifactMetadataRow.getColumnSlice() ) );
1893            }
1894        }
1895
1896        return mapArtifactMetadataToArtifact( metadataFacetResult, artifactMetadatas );
1897    }
1898
1899    @Override
1900    public List<ArtifactMetadata> getArtifactsByProperty( String key, String value, String repositoryId )
1901        throws MetadataRepositoryException
1902    {
1903        QueryResult<OrderedRows<String, String, String>> result =
1904            HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1905            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
1906            .setColumnNames( PROJECT_ID.toString(), REPOSITORY_NAME.toString(), NAMESPACE_ID.toString(),
1907                             PROJECT_VERSION.toString() ) //
1908            .addEqualsExpression( key, value ) //
1909            .execute();
1910
1911        int count = result.get().getCount();
1912
1913        if ( count < 1 )
1914        {
1915            return Collections.emptyList();
1916        }
1917
1918        List<ArtifactMetadata> artifacts = new LinkedList<ArtifactMetadata>();
1919
1920        for ( Row<String, String, String> row : result.get() )
1921        {
1922            // TODO doing multiple queries, there should be a way to get all the artifactMetadatas for any number of
1923            // projects
1924            try
1925            {
1926                artifacts.addAll( getArtifacts( getStringValue( row.getColumnSlice(), REPOSITORY_NAME ),
1927                                                getStringValue( row.getColumnSlice(), NAMESPACE_ID ),
1928                                                getStringValue( row.getColumnSlice(), PROJECT_ID ),
1929                                                getStringValue( row.getColumnSlice(), PROJECT_VERSION ) ) );
1930            }
1931            catch ( MetadataResolutionException e )
1932            {
1933                // never raised
1934                throw new IllegalStateException( e );
1935            }
1936        }
1937        return artifacts;
1938    }
1939
1940    @Override
1941    public void removeArtifact( final String repositoryId, final String namespace, final String project,
1942                                final String version, final String id )
1943        throws MetadataRepositoryException
1944    {
1945        logger.debug( "removeArtifact repositoryId: '{}', namespace: '{}', project: '{}', version: '{}', id: '{}'",
1946                      repositoryId, namespace, project, version, id );
1947        String key =
1948            new ArtifactMetadataModel.KeyBuilder().withRepositoryId( repositoryId ).withNamespace( namespace ).withId(
1949                id ).withProjectVersion( version ).withProject( project ).build();
1950
1951        this.artifactMetadataTemplate.deleteRow( key );
1952
1953        key = new ProjectVersionMetadataModel.KeyBuilder() //
1954            .withRepository( repositoryId ) //
1955            .withNamespace( namespace ) //
1956            .withProjectId( project ) //
1957            .withProjectVersion( version ) //
1958            .withId( id ) //
1959            .build();
1960
1961        this.projectVersionMetadataTemplate.deleteRow( key );
1962    }
1963
1964    @Override
1965    public void removeArtifact( ArtifactMetadata artifactMetadata, String baseVersion )
1966        throws MetadataRepositoryException
1967    {
1968        logger.debug( "removeArtifact repositoryId: '{}', namespace: '{}', project: '{}', version: '{}', id: '{}'",
1969                      artifactMetadata.getRepositoryId(), artifactMetadata.getNamespace(),
1970                      artifactMetadata.getProject(), baseVersion, artifactMetadata.getId() );
1971        String key =
1972            new ArtifactMetadataModel.KeyBuilder().withRepositoryId( artifactMetadata.getRepositoryId() ).withNamespace(
1973                artifactMetadata.getNamespace() ).withId( artifactMetadata.getId() ).withProjectVersion(
1974                baseVersion ).withProject( artifactMetadata.getProject() ).build();
1975
1976        this.artifactMetadataTemplate.deleteRow( key );
1977
1978    }
1979
1980    @Override
1981    public void removeArtifact( final String repositoryId, final String namespace, final String project,
1982                                final String version, final MetadataFacet metadataFacet )
1983        throws MetadataRepositoryException
1984    {
1985
1986        RangeSlicesQuery<String, String, String> query = HFactory //
1987            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
1988            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
1989            .setColumnNames( NAMESPACE_ID.toString() ); //
1990
1991        query = query.addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId ) //
1992            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
1993            .addEqualsExpression( PROJECT.toString(), project ) //
1994            .addEqualsExpression( VERSION.toString(), version );
1995
1996        QueryResult<OrderedRows<String, String, String>> result = query.execute();
1997
1998        for ( Row<String, String, String> row : result.get() )
1999        {
2000            this.artifactMetadataTemplate.deleteRow( row.getKey() );
2001        }
2002    }
2003
2004
2005    @Override
2006    public List<ArtifactMetadata> getArtifacts( final String repositoryId )
2007        throws MetadataRepositoryException
2008    {
2009
2010        RangeSlicesQuery<String, String, String> query = HFactory //
2011            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2012            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
2013            .setColumnNames( ArtifactMetadataModel.COLUMNS ); //
2014
2015        query = query.addEqualsExpression( REPOSITORY_NAME.toString(), repositoryId );
2016
2017        QueryResult<OrderedRows<String, String, String>> result = query.execute();
2018
2019        List<ArtifactMetadata> artifactMetadatas = new ArrayList<>( result.get().getCount() );
2020
2021        for ( Row<String, String, String> row : result.get() )
2022        {
2023            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
2024
2025            artifactMetadatas.add( mapArtifactMetadataStringColumnSlice( columnSlice ) );
2026
2027        }
2028
2029        return artifactMetadatas;
2030    }
2031
2032
2033    @Override
2034    public Collection<ProjectVersionReference> getProjectReferences( String repoId, String namespace, String projectId,
2035                                                                     String projectVersion )
2036        throws MetadataResolutionException
2037    {
2038        QueryResult<OrderedRows<String, String, String>> result = HFactory //
2039            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2040            .setColumnFamily( cassandraArchivaManager.getDependencyFamilyName() ) //
2041            .setColumnNames( "projectVersionMetadataModel.key" ) //
2042            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
2043            .addEqualsExpression( GROUP_ID.toString(), namespace ) //
2044            .addEqualsExpression( ARTIFACT_ID.toString(), projectId ) //
2045            .addEqualsExpression( VERSION.toString(), projectVersion ) //
2046            .execute();
2047
2048        List<String> dependenciesIds = new ArrayList<>( result.get().getCount() );
2049
2050        for ( Row<String, String, String> row : result.get().getList() )
2051        {
2052            dependenciesIds.add( getStringValue( row.getColumnSlice(), "projectVersionMetadataModel.key" ) );
2053        }
2054
2055        List<ProjectVersionReference> references = new ArrayList<>( result.get().getCount() );
2056
2057        for ( String key : dependenciesIds )
2058        {
2059            ColumnFamilyResult<String, String> columnFamilyResult =
2060                this.projectVersionMetadataTemplate.queryColumns( key );
2061            references.add( new ProjectVersionReference( ProjectVersionReference.ReferenceType.DEPENDENCY, //
2062                                                         columnFamilyResult.getString( PROJECT_ID.toString() ), //
2063                                                         columnFamilyResult.getString( NAMESPACE_ID.toString() ), //
2064                                                         columnFamilyResult.getString( PROJECT_VERSION.toString() ) ) );
2065        }
2066
2067        return references;
2068    }
2069
2070    @Override
2071    public void removeProjectVersion( final String repoId, final String namespace, final String projectId,
2072                                      final String projectVersion )
2073        throws MetadataRepositoryException
2074    {
2075
2076        QueryResult<OrderedRows<String, String, String>> result = HFactory //
2077            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2078            .setColumnFamily( cassandraArchivaManager.getProjectVersionMetadataFamilyName() ) //
2079            .setColumnNames( VERSION.toString() ) //
2080            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
2081            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
2082            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
2083            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
2084            .execute();
2085
2086        for ( Row<String, String, String> row : result.get().getList() )
2087        {
2088            this.projectVersionMetadataTemplate.deleteRow( row.getKey() );
2089            removeMailingList( row.getKey() );
2090            removeLicenses( row.getKey() );
2091            removeDependencies( row.getKey() );
2092        }
2093
2094        RangeSlicesQuery<String, String, String> query = HFactory //
2095            .createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2096            .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
2097            .setColumnNames( NAMESPACE_ID.toString() ); //
2098
2099        query = query.addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
2100            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
2101            .addEqualsExpression( PROJECT.toString(), projectId ) //
2102            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion );
2103
2104        result = query.execute();
2105
2106        for ( Row<String, String, String> row : result.get() )
2107        {
2108            this.artifactMetadataTemplate.deleteRow( row.getKey() );
2109
2110        }
2111    }
2112
2113    @Override
2114    public Collection<ArtifactMetadata> getArtifacts( final String repoId, final String namespace,
2115                                                      final String projectId, final String projectVersion )
2116        throws MetadataResolutionException
2117    {
2118
2119        QueryResult<OrderedRows<String, String, String>> result =
2120            HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2121                .setColumnFamily( cassandraArchivaManager.getArtifactMetadataFamilyName() ) //
2122                .setColumnNames( ArtifactMetadataModel.COLUMNS )//
2123                .setRowCount( Integer.MAX_VALUE ) //
2124                .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
2125                .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
2126                .addEqualsExpression( PROJECT.toString(), projectId ) //
2127                .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
2128                .execute();
2129
2130        if ( result.get() == null || result.get().getCount() < 1 )
2131        {
2132            return Collections.emptyList();
2133        }
2134
2135        List<ArtifactMetadata> artifactMetadatas = new ArrayList<>( result.get().getCount() );
2136
2137        for ( Row<String, String, String> row : result.get() )
2138        {
2139            artifactMetadatas.add( mapArtifactMetadataStringColumnSlice( row.getColumnSlice() ) );
2140        }
2141
2142        result = HFactory.createRangeSlicesQuery( keyspace, ss, ss, ss ) //
2143            .setColumnFamily( cassandraArchivaManager.getMetadataFacetFamilyName() ) //
2144            .setColumnNames( MetadataFacetModel.COLUMNS ) //
2145            .setRowCount( Integer.MAX_VALUE ) //
2146            .addEqualsExpression( REPOSITORY_NAME.toString(), repoId ) //
2147            .addEqualsExpression( NAMESPACE_ID.toString(), namespace ) //
2148            .addEqualsExpression( PROJECT_ID.toString(), projectId ) //
2149            .addEqualsExpression( PROJECT_VERSION.toString(), projectVersion ) //
2150            .execute();
2151
2152        return mapArtifactMetadataToArtifact(result, artifactMetadatas);
2153    }
2154
2155    /**
2156     * Attach metadata to each of the  ArtifactMetadata objects
2157     */
2158    private List<ArtifactMetadata> mapArtifactMetadataToArtifact(QueryResult<OrderedRows<String, String, String>> result, List<ArtifactMetadata> artifactMetadatas) {
2159        if ( result.get() == null || result.get().getCount() < 1 )
2160        {
2161            return artifactMetadatas;
2162        }
2163
2164        final List<MetadataFacetModel> metadataFacetModels = new ArrayList<>( result.get().getCount() );
2165
2166        for ( Row<String, String, String> row : result.get() )
2167        {
2168            ColumnSlice<String, String> columnSlice = row.getColumnSlice();
2169            MetadataFacetModel metadataFacetModel = new MetadataFacetModel();
2170            metadataFacetModel.setFacetId( getStringValue( columnSlice, FACET_ID.toString() ) );
2171            metadataFacetModel.setName( getStringValue( columnSlice, NAME.toString() ) );
2172            metadataFacetModel.setValue( getStringValue( columnSlice, VALUE.toString() ) );
2173            metadataFacetModel.setKey( getStringValue( columnSlice, KEY.toString() ) );
2174            metadataFacetModel.setProjectVersion( getStringValue( columnSlice, PROJECT_VERSION.toString() ) );
2175            metadataFacetModels.add( metadataFacetModel );
2176        }
2177
2178        // rebuild MetadataFacet for artifacts
2179
2180        for ( final ArtifactMetadata artifactMetadata : artifactMetadatas )
2181        {
2182            Iterable<MetadataFacetModel> metadataFacetModelIterable =
2183                Iterables.filter( metadataFacetModels, new Predicate<MetadataFacetModel>()
2184                {
2185                    @Override
2186                    public boolean apply( MetadataFacetModel metadataFacetModel )
2187                    {
2188                        if ( metadataFacetModel != null )
2189                        {
2190                            return StringUtils.equals( artifactMetadata.getVersion(),
2191                                                       metadataFacetModel.getProjectVersion() );
2192                        }
2193                        return false;
2194                    }
2195                } );
2196            Iterator<MetadataFacetModel> iterator = metadataFacetModelIterable.iterator();
2197            Map<String, List<MetadataFacetModel>> metadataFacetValuesPerFacetId = new HashMap<>();
2198            while ( iterator.hasNext() )
2199            {
2200                MetadataFacetModel metadataFacetModel = iterator.next();
2201                List<MetadataFacetModel> values = metadataFacetValuesPerFacetId.get( metadataFacetModel.getName() );
2202                if ( values == null )
2203                {
2204                    values = new ArrayList<>();
2205                    metadataFacetValuesPerFacetId.put( metadataFacetModel.getFacetId(), values );
2206                }
2207                values.add( metadataFacetModel );
2208
2209            }
2210
2211            for ( Map.Entry<String, List<MetadataFacetModel>> entry : metadataFacetValuesPerFacetId.entrySet() )
2212            {
2213                MetadataFacetFactory metadataFacetFactory = metadataFacetFactories.get( entry.getKey() );
2214                if ( metadataFacetFactory != null )
2215                {
2216                    List<MetadataFacetModel> facetModels = entry.getValue();
2217                    if ( !facetModels.isEmpty() )
2218                    {
2219                        MetadataFacet metadataFacet = metadataFacetFactory.createMetadataFacet();
2220                        Map<String, String> props = new HashMap<>( facetModels.size() );
2221                        for ( MetadataFacetModel metadataFacetModel : facetModels )
2222                        {
2223                            props.put( metadataFacetModel.getKey(), metadataFacetModel.getValue() );
2224                        }
2225                        metadataFacet.fromProperties( props );
2226                        artifactMetadata.addFacet( metadataFacet );
2227                    }
2228                }
2229            }
2230        }
2231
2232        return artifactMetadatas;
2233    }
2234
2235    @Override
2236    public void save()
2237    {
2238        logger.trace( "save" );
2239    }
2240
2241    @Override
2242    public void close()
2243        throws MetadataRepositoryException
2244    {
2245        logger.trace( "close" );
2246    }
2247
2248    @Override
2249    public void revert()
2250    {
2251        logger.warn( "CassandraMetadataRepository cannot revert" );
2252    }
2253
2254    @Override
2255    public boolean canObtainAccess( Class<?> aClass )
2256    {
2257        return false;
2258    }
2259
2260    @Override
2261    public <T> T obtainAccess( Class<T> aClass )
2262        throws MetadataRepositoryException
2263    {
2264        throw new IllegalArgumentException(
2265            "Access using " + aClass + " is not supported on the cassandra metadata storage" );
2266    }
2267
2268
2269    private static class ModelMapperHolder
2270    {
2271        private static ModelMapper MODEL_MAPPER = new ModelMapper();
2272    }
2273
2274    protected ModelMapper getModelMapper()
2275    {
2276        return ModelMapperHolder.MODEL_MAPPER;
2277    }
2278
2279    /**
2280     * This implementation just calls getArtifactsByMetadata( null, text, repositoryId ). We can't search artifacts by
2281     * any property.
2282     */
2283    @Override
2284    public List<ArtifactMetadata> searchArtifacts( String text, String repositoryId, boolean exact )
2285        throws MetadataRepositoryException
2286    {
2287        return getArtifactsByMetadata( null, text, repositoryId );
2288    }
2289
2290    /**
2291     * The exact parameter is ignored as we can't do non exact searches in Cassandra
2292     */
2293    @Override
2294    public List<ArtifactMetadata> searchArtifacts( String key, String text, String repositoryId, boolean exact )
2295        throws MetadataRepositoryException
2296    {
2297        // TODO optimize
2298        List<ArtifactMetadata> artifacts = new LinkedList<ArtifactMetadata>();
2299        artifacts.addAll( getArtifactsByMetadata( key, text, repositoryId ) );
2300        artifacts.addAll( getArtifactsByProperty( key, text, repositoryId ) );
2301        return artifacts;
2302    }
2303}