1 package org.apache.archiva.metadata.repository.cassandra;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import com.datastax.oss.driver.api.core.CqlSession;
23 import com.datastax.oss.driver.api.core.CqlSessionBuilder;
24 import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
25 import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
26 import com.datastax.oss.driver.api.core.type.DataTypes;
27 import com.datastax.oss.driver.api.querybuilder.schema.CreateIndex;
28 import com.datastax.oss.driver.api.querybuilder.schema.CreateKeyspace;
29 import com.datastax.oss.driver.api.querybuilder.schema.CreateTableWithOptions;
30 import org.apache.archiva.metadata.repository.RepositorySessionFactoryBean;
31 import org.apache.commons.lang3.StringUtils;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.beans.factory.annotation.Value;
35 import org.springframework.context.ApplicationContext;
36 import org.springframework.stereotype.Service;
38 import javax.annotation.PostConstruct;
39 import javax.annotation.PreDestroy;
40 import javax.inject.Inject;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.List;
45 import static com.datastax.oss.driver.api.querybuilder.SchemaBuilder.*;
46 import static org.apache.archiva.metadata.repository.cassandra.model.ColumnNames.*;
49 * FIXME make all configuration not hardcoded :-)
51 * @author Olivier Lamy
54 @Service( "archivaEntityManagerFactory#cassandra" )
55 public class DefaultCassandraArchivaManager
56 implements CassandraArchivaManager
59 private static final Logger logger = LoggerFactory.getLogger( DefaultCassandraArchivaManager.class );
62 private ApplicationContext applicationContext;
64 private static final String CLUSTER_NAME = "archiva";
66 private static final String KEYSPACE_NAME = "ArchivaKeySpace";
68 private boolean started;
71 private String repositoryFamilyName = "repository";
73 private String namespaceFamilyName = "namespace";
75 private String projectFamilyName = PROJECT.toString( );
77 private String projectVersionMetadataFamilyName = "projectversionmetadata";
79 private String artifactMetadataFamilyName = "artifactmetadata";
81 private String metadataFacetFamilyName = "metadatafacet";
83 private String mailingListFamilyName = "mailinglist";
85 private String licenseFamilyName = "license";
87 private String dependencyFamilyName = "dependency";
89 private String checksumFamilyName = "checksum";
92 private static String[] projectVersionMetadataColumns;
97 projectVersionMetadataColumns = new String[]{
99 NAMESPACE_ID.toString( ),
100 REPOSITORY_NAME.toString( ),
101 PROJECT_VERSION.toString( ),
102 PROJECT_ID.toString( ),
103 DESCRIPTION.toString( ),
107 VERSION_PROPERTIES.toString( ),
109 "ciManagement.system",
111 "issueManagement.system",
112 "issueManagement.url",
117 "scm.developerConnection"
119 Arrays.sort( projectVersionMetadataColumns );
122 @Value( "${cassandra.host}" )
123 private String cassandraHost;
125 @Value( "${cassandra.port}" )
126 private String cassandraPort;
128 @Value( "${cassandra.maxActive}" )
129 private int maxActive;
131 @Value( "${cassandra.readConsistencyLevel}" )
132 private String readConsistencyLevel;
134 @Value( "${cassandra.writeConsistencyLevel}" )
135 private String writeConsistencyLevel;
137 @Value( "${cassandra.replicationFactor}" )
138 private int replicationFactor;
140 @Value( "${cassandra.keyspace.name}" )
141 private String keyspaceName;
143 @Value( "${cassandra.cluster.name}" )
144 private String clusterName;
147 private RepositorySessionFactoryBean repositorySessionFactoryBean;
149 DriverConfigLoader configLoader;
151 CqlSession cqlSession;
154 public CqlSessionBuilder getSessionBuilder( )
156 return CqlSession.builder( ).withConfigLoader( configLoader ).withKeyspace( keyspaceName ).withLocalDatacenter( "datacenter1" );
160 public CqlSession getSession( )
162 if (cqlSession==null || cqlSession.isClosed()) {
163 this.cqlSession = getSessionBuilder( ).build( );
165 return this.cqlSession;
169 public void initialize( )
171 // skip initialisation if not cassandra
172 if ( !StringUtils.equals( repositorySessionFactoryBean.getId( ), "cassandra" ) )
177 List<String> hostNames = new ArrayList<>( );
178 hostNames.add( cassandraHost + ":" + cassandraPort );
179 System.out.println( "Contact point: " + cassandraHost + ":" + cassandraPort );
181 DriverConfigLoader.programmaticBuilder( )
183 .withStringList( DefaultDriverOption.CONTACT_POINTS, hostNames )
184 .withInt( DefaultDriverOption.CONNECTION_POOL_LOCAL_SIZE, maxActive )
185 .withInt( DefaultDriverOption.CONNECTION_POOL_REMOTE_SIZE, maxActive )
186 //.withInt( DefaultDriverOption.CONNECTION_MAX_REQUESTS, maxActive )
187 .withString( DefaultDriverOption.REQUEST_CONSISTENCY, readConsistencyLevel )
192 CreateKeyspace cKeySpace = createKeyspace( keyspaceName ).ifNotExists( ).withSimpleStrategy( replicationFactor );
193 CqlSession.builder( ).withConfigLoader( configLoader ).withLocalDatacenter( "datacenter1" ).build().execute( cKeySpace.build( ) );
196 CqlSession session = getSession( );
202 String tableName = getNamespaceFamilyName( );
203 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
204 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
205 .withColumn( NAME.toString( ), DataTypes.TEXT )
206 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
207 .withCompactStorage( );
208 session.execute( table.build( ) );
209 CreateIndex index = createIndex( NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAME.toString( ) );
210 session.execute( index.build( ) );
211 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
212 session.execute( index.build( ) );
217 String tableName = getRepositoryFamilyName( );
218 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
219 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
220 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
221 .withCompactStorage( );
222 session.execute( table.build( ) );
223 CreateIndex index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
224 session.execute( index.build( ) );
230 String tableName = getProjectFamilyName( );
231 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
232 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
233 .withColumn( PROJECT_ID.toString( ), DataTypes.TEXT )
234 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
235 .withColumn( NAMESPACE_ID.toString( ), DataTypes.TEXT )
236 .withColumn( PROJECT_PROPERTIES.toString( ), DataTypes.frozenMapOf( DataTypes.TEXT, DataTypes.TEXT ) )
237 .withCompactStorage( );
238 session.execute( table.build( ) );
239 CreateIndex index = createIndex( PROJECT_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_ID.toString( ) );
240 session.execute( index.build( ) );
241 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
242 session.execute( index.build( ) );
243 index = createIndex( NAMESPACE_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAMESPACE_ID.toString( ) );
244 session.execute( index.build( ) );
248 // Project Version Metadata Model
250 String tableName = getProjectVersionMetadataFamilyName( );
251 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
252 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
253 .withColumn( NAMESPACE_ID.toString( ), DataTypes.TEXT )
254 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
255 .withColumn( PROJECT_VERSION.toString( ), DataTypes.TEXT )
256 .withColumn( PROJECT_ID.toString( ), DataTypes.TEXT )
257 .withColumn( DESCRIPTION.toString( ), DataTypes.TEXT )
258 .withColumn( URL.toString( ), DataTypes.TEXT )
259 .withColumn( NAME.toString(), DataTypes.TEXT )
260 .withColumn( VERSION.toString(), DataTypes.TEXT )
261 .withColumn( VERSION_PROPERTIES.toString(), DataTypes.mapOf( DataTypes.TEXT, DataTypes.TEXT ) )
262 .withColumn( "incomplete", DataTypes.BOOLEAN )
263 .withColumn( "\"ciManagement.system\"", DataTypes.TEXT )
264 .withColumn( "\"ciManagement.url\"", DataTypes.TEXT )
265 .withColumn( "\"issueManagement.system\"", DataTypes.TEXT )
266 .withColumn( "\"issueManagement.url\"", DataTypes.TEXT )
267 .withColumn( "\"organization.name\"", DataTypes.TEXT )
268 .withColumn( "\"organization.url\"", DataTypes.TEXT )
269 .withColumn( "\"scm.url\"", DataTypes.TEXT )
270 .withColumn( "\"scm.connection\"", DataTypes.TEXT )
271 .withColumn( "\"scm.developerConnection\"", DataTypes.TEXT );
272 session.execute( table.build( ) );
273 CreateIndex index = createIndex( NAMESPACE_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAMESPACE_ID.toString( ) );
274 session.execute( index.build( ) );
275 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
276 session.execute( index.build( ) );
277 index = createIndex( PROJECT_VERSION.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_VERSION.toString( ) );
278 session.execute( index.build( ) );
279 index = createIndex( PROJECT_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_ID.toString( ) );
280 session.execute( index.build( ) );
281 index = createIndex( VERSION_PROPERTIES.toString( ) + "_idx" ).ifNotExists( ).onTable( tableName ).andColumnEntries( VERSION_PROPERTIES.toString( ) );
282 session.execute( index.build( ) );
285 // Artifact Metadata Model
287 String tableName = getArtifactMetadataFamilyName( );
288 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
289 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
290 .withColumn( ID.toString( ), DataTypes.TEXT )
291 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
292 .withColumn( NAMESPACE_ID.toString( ), DataTypes.TEXT )
293 .withColumn( PROJECT_ID.toString( ), DataTypes.TEXT )
294 .withColumn( PROJECT_VERSION.toString( ), DataTypes.TEXT )
295 .withColumn( VERSION.toString( ), DataTypes.TEXT )
296 .withColumn( WHEN_GATHERED.toString( ), DataTypes.BIGINT )
297 .withColumn( SHA1.toString( ), DataTypes.TEXT )
298 .withColumn( MD5.toString( ), DataTypes.TEXT )
299 .withColumn( FILE_LAST_MODIFIED.toString(), DataTypes.BIGINT)
300 .withColumn( SIZE.toString(), DataTypes.BIGINT )
301 .withCompactStorage( );
302 session.execute( table.build( ) );
304 CreateIndex index = createIndex( ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( ID.toString( ) );
305 session.execute( index.build( ) );
306 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
307 session.execute( index.build( ) );
308 index = createIndex( NAMESPACE_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAMESPACE_ID.toString( ) );
309 session.execute( index.build( ) );
310 index = createIndex( PROJECT_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_ID.toString( ) );
311 session.execute( index.build( ) );
312 index = createIndex( PROJECT_VERSION.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_VERSION.toString( ) );
313 session.execute( index.build( ) );
314 index = createIndex( VERSION.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( VERSION.toString( ) );
315 session.execute( index.build( ) );
316 index = createIndex( WHEN_GATHERED.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( WHEN_GATHERED.toString( ) );
317 session.execute( index.build( ) );
318 index = createIndex( SHA1.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( SHA1.toString( ) );
319 session.execute( index.build( ) );
320 index = createIndex( MD5.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( MD5.toString( ) );
321 session.execute( index.build( ) );
324 // Metadata Facet Model
326 String tableName = getMetadataFacetFamilyName( );
327 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
328 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
329 .withColumn( FACET_ID.toString( ), DataTypes.TEXT )
330 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
331 .withColumn( NAME.toString( ), DataTypes.TEXT )
332 .withColumn( NAMESPACE_ID.toString( ), DataTypes.TEXT )
333 .withColumn( PROJECT_ID.toString( ), DataTypes.TEXT )
334 .withColumn( PROJECT_VERSION.toString( ), DataTypes.TEXT )
335 .withColumn( KEY.toString(), DataTypes.TEXT )
336 .withColumn( VALUE.toString(), DataTypes.TEXT)
337 .withColumn( WHEN_GATHERED.toString(), DataTypes.BIGINT )
338 .withCompactStorage( );
339 session.execute( table.build( ) );
341 CreateIndex index = createIndex( FACET_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( FACET_ID.toString( ) );
342 session.execute( index.build( ) );
343 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
344 session.execute( index.build( ) );
345 index = createIndex( NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAME.toString( ) );
346 session.execute( index.build( ) );
347 index = createIndex( NAMESPACE_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( NAMESPACE_ID.toString( ) );
348 session.execute( index.build( ) );
349 index = createIndex( PROJECT_ID.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_ID.toString( ) );
350 session.execute( index.build( ) );
351 index = createIndex( PROJECT_VERSION.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( PROJECT_VERSION.toString( ) );
352 session.execute( index.build( ) );
356 String tableName = getChecksumFamilyName( );
357 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
358 .withPartitionKey( DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
359 .withColumn( "\"artifactMetadataModel.key\"", DataTypes.TEXT )
360 .withColumn( CHECKSUM_ALG.toString( ), DataTypes.TEXT )
361 .withColumn( CHECKSUM_VALUE.toString( ), DataTypes.TEXT )
362 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
363 .withCompactStorage( );
364 session.execute( table.build( ) );
366 CreateIndex index = createIndex( CHECKSUM_ALG.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( CHECKSUM_ALG.toString( ) );
367 session.execute( index.build( ) );
368 index = createIndex( CHECKSUM_VALUE.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( CHECKSUM_VALUE.toString( ) );
369 session.execute( index.build( ) );
370 index = createIndex( REPOSITORY_NAME.toString( ) ).ifNotExists( ).onTable( tableName ).andColumn( REPOSITORY_NAME.toString( ) );
371 session.execute( index.build( ) );
375 String tableName = getMailingListFamilyName( );
376 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
377 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
378 .withColumn( NAME.toString(), DataTypes.TEXT )
379 .withColumn( "\"projectVersionMetadataModel.key\"", DataTypes.TEXT )
380 .withColumn( "mainArchiveUrl", DataTypes.TEXT )
381 .withColumn( "postAddress", DataTypes.TEXT )
382 .withColumn( "subscribeAddress", DataTypes.TEXT )
383 .withColumn( "unsubscribeAddress", DataTypes.TEXT )
384 .withColumn( "otherArchive", DataTypes.frozenListOf( DataTypes.TEXT ) )
385 .withCompactStorage( );
386 session.execute( table.build( ) );
388 CreateIndex index = createIndex( "\"projectVersionMetadataModel_key\"" ).ifNotExists( ).onTable( tableName ).andColumn( "\"\"projectVersionMetadataModel.key\"\"" );
389 session.execute( index.build( ) );
394 String tableName = getLicenseFamilyName( );
395 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
396 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
397 .withColumn( "\"projectVersionMetadataModel.key\"", DataTypes.TEXT )
398 .withColumn( NAME.toString(), DataTypes.TEXT )
399 .withColumn( URL.toString(), DataTypes.TEXT )
400 .withCompactStorage( );
401 session.execute( table.build( ) );
403 CreateIndex index = createIndex( "\"projectVersionMetadataModel_key\"" ).ifNotExists( ).onTable( tableName ).andColumn( "\"\"projectVersionMetadataModel.key\"\"" );
404 session.execute( index.build( ) );
409 String tableName = getDependencyFamilyName( );
410 CreateTableWithOptions table = createTable( keyspaceName, tableName ).ifNotExists( )
411 .withPartitionKey( CassandraArchivaManager.DEFAULT_PRIMARY_KEY, DataTypes.TEXT )
412 .withColumn( REPOSITORY_NAME.toString( ), DataTypes.TEXT )
413 .withColumn( GROUP_ID.toString( ), DataTypes.TEXT )
414 .withColumn( ARTIFACT_ID.toString( ), DataTypes.TEXT )
415 .withColumn( VERSION.toString( ), DataTypes.TEXT )
416 .withColumn( "\"projectVersionMetadataModel.key\"", DataTypes.TEXT )
417 .withColumn( "classifier", DataTypes.TEXT )
418 .withColumn( "optional", DataTypes.TEXT )
419 .withColumn( "scope", DataTypes.TEXT )
420 .withColumn( "systemPath", DataTypes.TEXT )
421 .withColumn( "type", DataTypes.TEXT )
422 .withCompactStorage( );
424 session.execute( table.build( ) );
426 CreateIndex index = createIndex( "groupIdIdx" ).ifNotExists( ).onTable( tableName ).andColumn( GROUP_ID.toString( ) );
427 session.execute( index.build( ) );
428 index = createIndex( "\"projectVersionMetadataModel_key\"" ).ifNotExists( ).onTable( tableName ).andColumn( "\"\"projectVersionMetadataModel.key\"\"" );
429 session.execute( index.build( ) );
445 public void shutdown( )
447 if (this.cqlSession!=null) {
448 this.cqlSession.close( );
454 public boolean started( )
461 public String getRepositoryFamilyName( )
463 return repositoryFamilyName;
467 public String getNamespaceFamilyName( )
469 return namespaceFamilyName;
473 public String getProjectFamilyName( )
475 return projectFamilyName;
479 public String getProjectVersionMetadataFamilyName( )
481 return projectVersionMetadataFamilyName;
484 public String[] getProjectVersionMetadataColumns() {
485 return projectVersionMetadataColumns;
489 public String getArtifactMetadataFamilyName( )
491 return artifactMetadataFamilyName;
495 public String getMetadataFacetFamilyName( )
497 return metadataFacetFamilyName;
501 public String getMailingListFamilyName( )
503 return mailingListFamilyName;
507 public String getLicenseFamilyName( )
509 return licenseFamilyName;
513 public String getDependencyFamilyName( )
515 return dependencyFamilyName;
519 public String getChecksumFamilyName( )
521 return checksumFamilyName;
525 public DriverConfigLoader getConfigLoader( )
531 public String getKeyspaceName( )