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