001package org.apache.archiva.metadata.repository.jcr; 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.collect.ImmutableList; 023import com.google.common.collect.ImmutableSet; 024import org.apache.commons.lang3.time.StopWatch; 025import org.apache.jackrabbit.oak.api.Type; 026import org.apache.jackrabbit.oak.jcr.Jcr; 027import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService; 028import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoServiceImpl; 029import org.apache.jackrabbit.oak.plugins.index.IndexInfoProvider; 030import org.apache.jackrabbit.oak.plugins.index.IndexPathService; 031import org.apache.jackrabbit.oak.plugins.index.IndexPathServiceImpl; 032import org.apache.jackrabbit.oak.plugins.index.IndexUtils; 033import org.apache.jackrabbit.oak.plugins.index.aggregate.SimpleNodeAggregator; 034import org.apache.jackrabbit.oak.plugins.index.lucene.IndexAugmentorFactory; 035import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier; 036import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker; 037import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider; 038import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexInfoProvider; 039import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProvider; 040import org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory; 041import org.apache.jackrabbit.oak.plugins.index.lucene.directory.BufferedOakDirectory; 042import org.apache.jackrabbit.oak.plugins.index.lucene.directory.LuceneIndexImporter; 043import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.DocumentQueue; 044import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.ExternalObserverBuilder; 045import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.LocalIndexObserver; 046import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.NRTIndexFactory; 047import org.apache.jackrabbit.oak.plugins.index.lucene.property.PropertyIndexCleaner; 048import org.apache.jackrabbit.oak.plugins.index.lucene.reader.DefaultIndexReaderFactory; 049import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory; 050import org.apache.jackrabbit.oak.plugins.index.lucene.score.impl.ScorerProviderFactoryImpl; 051import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder; 052import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache; 053import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants; 054import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore; 055import org.apache.jackrabbit.oak.plugins.name.Namespaces; 056import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders; 057import org.apache.jackrabbit.oak.segment.file.FileStore; 058import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder; 059import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException; 060import org.apache.jackrabbit.oak.spi.blob.FileBlobStore; 061import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore; 062import org.apache.jackrabbit.oak.spi.commit.BackgroundObserver; 063import org.apache.jackrabbit.oak.spi.commit.Observer; 064import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer; 065import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; 066import org.apache.jackrabbit.oak.spi.mount.Mounts; 067import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants; 068import org.apache.jackrabbit.oak.spi.query.QueryIndex; 069import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider; 070import org.apache.jackrabbit.oak.spi.state.Clusterable; 071import org.apache.jackrabbit.oak.spi.state.NodeBuilder; 072import org.apache.jackrabbit.oak.spi.state.NodeStore; 073import org.apache.jackrabbit.oak.stats.StatisticsProvider; 074import org.jetbrains.annotations.NotNull; 075import org.slf4j.Logger; 076import org.slf4j.LoggerFactory; 077 078import javax.jcr.Repository; 079import java.io.Closeable; 080import java.io.IOException; 081import java.nio.file.Files; 082import java.nio.file.Path; 083import java.nio.file.Paths; 084import java.util.concurrent.ExecutorService; 085import java.util.concurrent.LinkedBlockingQueue; 086import java.util.concurrent.ThreadFactory; 087import java.util.concurrent.ThreadPoolExecutor; 088import java.util.concurrent.TimeUnit; 089import java.util.concurrent.atomic.AtomicInteger; 090 091import static com.google.common.base.Preconditions.checkNotNull; 092import static org.apache.archiva.metadata.repository.jcr.JcrConstants.*; 093import static org.apache.archiva.metadata.repository.jcr.OakRepositoryFactory.StoreType.IN_MEMORY_TYPE; 094import static org.apache.archiva.metadata.repository.jcr.OakRepositoryFactory.StoreType.SEGMENT_FILE_TYPE; 095import static org.apache.commons.io.FileUtils.ONE_MB; 096import static org.apache.jackrabbit.JcrConstants.*; 097import static org.apache.jackrabbit.oak.api.Type.NAME; 098 099/** 100 * Created by martin on 14.06.17. 101 * 102 * @author Martin Stockhammer 103 * @since 3.0.0 104 */ 105public class OakRepositoryFactory 106{ 107 108 private Logger log = LoggerFactory.getLogger( OakRepositoryFactory.class ); 109 110 private FileStore fileStore; 111 112 private NodeStore nodeStore; 113 114 private IndexTracker tracker; 115 116 private DocumentQueue documentQueue; 117 118 private NRTIndexFactory nrtIndexFactory; 119 120 private IndexCopier indexCopier; 121 122 private ExecutorService executorService; 123 private ExtractedTextCache extractedTextCache; 124 125 private boolean hybridIndex = true; 126 private boolean prefetchEnabled = true; 127 private boolean enableAsyncIndexOpen = true; 128 int queueSize = 10000; 129 int cleanerInterval = 10*60; 130 boolean enableCopyOnWrite = true; 131 boolean enableCopyOnRead = true; 132 int cacheSizeInMB = 20; 133 int cacheExpiryInSecs = 300; 134 int threadPoolSize = 5; 135 136 private StatisticsProvider statisticsProvider; 137 138 private MountInfoProvider mountInfoProvider = Mounts.defaultMountInfoProvider(); 139 140 private AsyncIndexInfoService asyncIndexInfoService = null; 141 142 private LuceneIndexProvider indexProvider; 143 144 private ScorerProviderFactory scorerFactory = new ScorerProviderFactoryImpl( ); 145 private IndexAugmentorFactory augmentorFactory = new IndexAugmentorFactory( ); 146 147 private ActiveDeletedBlobCollectorFactory.ActiveDeletedBlobCollector activeDeletedBlobCollector = ActiveDeletedBlobCollectorFactory.NOOP; 148 149 private QueryIndex.NodeAggregator nodeAggregator = new SimpleNodeAggregator( ); 150 151 private BackgroundObserver backgroundObserver; 152 153 private BackgroundObserver externalIndexObserver; 154 155 private GarbageCollectableBlobStore blobStore; 156 157 private PropertyIndexCleaner cleaner; 158 159 private IndexPathService indexPathService; 160 161 private LuceneIndexEditorProvider editorProvider; 162 163 private Path indexDir; 164 165 public enum StoreType 166 { 167 SEGMENT_FILE_TYPE, 168 IN_MEMORY_TYPE; 169 } 170 171 private StoreType storeType = SEGMENT_FILE_TYPE; 172 173 private Path repositoryPath = Paths.get( "repository" ); 174 175 public OakRepositoryFactory() { 176 final OakRepositoryFactory repositoryFactory = this; 177 Runtime.getRuntime().addShutdownHook( new Thread( ( ) -> { 178 if (repositoryFactory!=null) 179 { 180 repositoryFactory.close( ); 181 } 182 } ) ); 183 } 184 185 private void initializeExtractedTextCache( StatisticsProvider statisticsProvider) { 186 boolean alwaysUsePreExtractedCache = false; 187 188 extractedTextCache = new ExtractedTextCache( 189 cacheSizeInMB * ONE_MB, 190 cacheExpiryInSecs, 191 alwaysUsePreExtractedCache, 192 indexDir.toFile(), statisticsProvider); 193 } 194 195 private IndexTracker createTracker() throws IOException { 196 IndexTracker tracker; 197 if (enableCopyOnRead){ 198 initializeIndexCopier(); 199 log.info("Enabling CopyOnRead support. Index files would be copied under {}", indexDir.toAbsolutePath()); 200 if (hybridIndex) { 201 nrtIndexFactory = new NRTIndexFactory(indexCopier, statisticsProvider); 202 } 203 tracker = new IndexTracker(new DefaultIndexReaderFactory(mountInfoProvider, indexCopier), nrtIndexFactory); 204 } else { 205 tracker = new IndexTracker(new DefaultIndexReaderFactory(mountInfoProvider, null)); 206 } 207 208 tracker.setAsyncIndexInfoService(asyncIndexInfoService); 209 tracker.refresh(); 210 return tracker; 211 } 212 213 private void initializeIndexCopier() throws IOException { 214 if(indexCopier != null){ 215 return; 216 } 217 218 if (prefetchEnabled){ 219 log.info("Prefetching of index files enabled. Index would be opened after copying all new files locally"); 220 } 221 222 indexCopier = new IndexCopier(getExecutorService(), indexDir.toFile(), prefetchEnabled); 223 224 } 225 226 ExecutorService getExecutorService(){ 227 if (executorService == null){ 228 executorService = createExecutor(); 229 } 230 return executorService; 231 } 232 233 private ExecutorService createExecutor() { 234 ThreadPoolExecutor executor = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 60L, TimeUnit.SECONDS, 235 new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { 236 private final AtomicInteger counter = new AtomicInteger(); 237 private final Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() { 238 @Override 239 public void uncaughtException(Thread t, Throwable e) { 240 log.warn("Error occurred in asynchronous processing ", e); 241 } 242 }; 243 @Override 244 public Thread newThread(@NotNull Runnable r) { 245 Thread thread = new Thread(r, createName()); 246 thread.setDaemon(true); 247 thread.setPriority(Thread.MIN_PRIORITY); 248 thread.setUncaughtExceptionHandler(handler); 249 return thread; 250 } 251 252 private String createName() { 253 return "oak-lucene-" + counter.getAndIncrement(); 254 } 255 }); 256 executor.setKeepAliveTime(1, TimeUnit.MINUTES); 257 executor.allowCoreThreadTimeOut(true); 258 return executor; 259 } 260 261 private void initialize(){ 262 if(indexProvider == null){ 263 return; 264 } 265 266 if(nodeAggregator != null){ 267 log.debug("Using NodeAggregator {}", nodeAggregator.getClass()); 268 } 269 270 indexProvider.setAggregator(nodeAggregator); 271 } 272 273 private void registerObserver() { 274 Observer observer = indexProvider; 275 if (enableAsyncIndexOpen) { 276 backgroundObserver = new BackgroundObserver(indexProvider, getExecutorService(), 5); 277 log.info("Registering the LuceneIndexProvider as a BackgroundObserver"); 278 } 279 } 280 281 private void registerLocalIndexObserver(IndexTracker tracker) { 282 if (!hybridIndex){ 283 log.info("Hybrid indexing feature disabled"); 284 return; 285 } 286 documentQueue = new DocumentQueue( queueSize, tracker, getExecutorService(), statisticsProvider); 287 LocalIndexObserver localIndexObserver = new LocalIndexObserver(documentQueue, statisticsProvider); 288 289 int observerQueueSize = 1000; 290 int builderMaxSize = 5000; 291 // regs.add(bundleContext.registerService(JournalPropertyService.class.getName(), 292 // new LuceneJournalPropertyService(builderMaxSize), null)); 293 ExternalObserverBuilder builder = new ExternalObserverBuilder(documentQueue, tracker, statisticsProvider, 294 getExecutorService(), observerQueueSize); 295 log.info("Configured JournalPropertyBuilder with max size {} and backed by BackgroundObserver " + 296 "with queue size {}", builderMaxSize, observerQueueSize); 297 298 Observer observer = builder.build(); 299 externalIndexObserver = builder.getBackgroundObserver(); 300 log.info("Hybrid indexing enabled for configured indexes with queue size of {}", queueSize ); 301 } 302 303 private IndexInfoProvider registerIndexInfoProvider() { 304 return new LuceneIndexInfoProvider(nodeStore, asyncIndexInfoService, getIndexCheckDir().toFile()); 305 } 306 307 private Path getIndexCheckDir() { 308 return checkNotNull(indexDir).resolve("indexCheckDir"); 309 } 310 311 private LuceneIndexImporter registerIndexImporterProvider() { 312 return new LuceneIndexImporter(blobStore); 313 } 314 315 private void registerPropertyIndexCleaner( ) { 316 317 if (cleanerInterval <= 0) { 318 log.info("Property index cleaner would not be registered"); 319 return; 320 } 321 322 cleaner = new PropertyIndexCleaner(nodeStore, indexPathService, asyncIndexInfoService, statisticsProvider); 323 324 //Proxy check for DocumentNodeStore 325 if (nodeStore instanceof Clusterable ) { 326 cleaner.setRecursiveDelete(true); 327 log.info("PropertyIndexCleaner configured to perform recursive delete"); 328 } 329 log.info("Property index cleaner configured to run every [{}] seconds", cleanerInterval); 330 } 331 332 private void registerIndexEditor( IndexTracker tracker) throws IOException { 333 boolean enableCopyOnWrite = true; 334 if (enableCopyOnWrite){ 335 initializeIndexCopier(); 336 editorProvider = new LuceneIndexEditorProvider(indexCopier, tracker, extractedTextCache, 337 augmentorFactory, mountInfoProvider, activeDeletedBlobCollector, null, statisticsProvider); 338 log.info("Enabling CopyOnWrite support. Index files would be copied under {}", indexDir.toAbsolutePath()); 339 } else { 340 editorProvider = new LuceneIndexEditorProvider(null, tracker, extractedTextCache, augmentorFactory, 341 mountInfoProvider, activeDeletedBlobCollector, null, statisticsProvider); 342 } 343 editorProvider.setBlobStore(blobStore); 344 345 if (hybridIndex){ 346 editorProvider.setIndexingQueue(checkNotNull(documentQueue)); 347 } 348 349 350 } 351 352 public Repository createRepository() 353 throws IOException, InvalidFileStoreVersionException 354 { 355 356 indexDir = repositoryPath.resolve( ".index-lucene" ); 357 if (!Files.exists( indexDir )) { 358 Files.createDirectories( indexDir ); 359 } 360 blobStore = new FileBlobStore( indexDir.resolve( "blobs" ).toAbsolutePath().toString() ); 361 362 statisticsProvider = StatisticsProvider.NOOP; 363 364 if ( SEGMENT_FILE_TYPE == storeType ) 365 { 366 fileStore = FileStoreBuilder.fileStoreBuilder( repositoryPath.toFile() ) 367 .withStatisticsProvider( statisticsProvider ) 368 .build(); 369 nodeStore = SegmentNodeStoreBuilders.builder( fileStore ) // 370 .withStatisticsProvider( statisticsProvider ) // 371 .build(); 372 } 373 else if ( IN_MEMORY_TYPE == storeType ) 374 { 375 nodeStore = new MemoryNodeStore( ); 376 } 377 else 378 { 379 throw new IllegalArgumentException( "Store type " + storeType + " not recognized" ); 380 } 381 382 asyncIndexInfoService = new AsyncIndexInfoServiceImpl( nodeStore ); 383 384 indexPathService = new IndexPathServiceImpl( nodeStore, mountInfoProvider ); 385 386 BufferedOakDirectory.setEnableWritingSingleBlobIndexFile( true ); 387 388 initializeExtractedTextCache( statisticsProvider ); 389 390 tracker = createTracker(); 391 392 indexProvider = new LuceneIndexProvider(tracker, scorerFactory, augmentorFactory); 393 394 initialize(); 395 registerObserver(); 396 registerLocalIndexObserver(tracker); 397 registerIndexInfoProvider(); 398 registerIndexImporterProvider(); 399 registerPropertyIndexCleaner(); 400 401 registerIndexEditor(tracker); 402 403 404 405 RepositoryInitializer repoInitializer = new RepositoryInitializer( ) 406 { 407 private IndexDefinitionBuilder.PropertyRule initRegexAll( IndexDefinitionBuilder.IndexRule rule ) { 408 return rule 409 .indexNodeName( ) 410 .property(JCR_LASTMODIFIED ).propertyIndex().type( "Date" ).ordered() 411 .property(JCR_PRIMARYTYPE).propertyIndex() 412 .property(JCR_MIXINTYPES).propertyIndex() 413 .property(JCR_PATH).propertyIndex().ordered() 414 .property( FulltextIndexConstants.REGEX_ALL_PROPS, true ) 415 .propertyIndex().analyzed( ).nodeScopeIndex(); 416 } 417 418 private IndexDefinitionBuilder.PropertyRule initBaseRule( IndexDefinitionBuilder.IndexRule rule ) { 419 return rule 420 .indexNodeName( ) 421 .property(JCR_CREATED).propertyIndex().type("Date").ordered() 422 .property(JCR_LASTMODIFIED ).propertyIndex().type( "Date" ).ordered() 423 .property(JCR_PRIMARYTYPE).propertyIndex() 424 .property(JCR_MIXINTYPES).propertyIndex() 425 .property(JCR_PATH).propertyIndex().ordered() 426 .property( "id" ).propertyIndex().analyzed( ); 427 } 428 429 @Override 430 public void initialize( NodeBuilder root ) 431 { 432 NodeBuilder namespaces; 433 if ( !root.hasChildNode( NamespaceConstants.REP_NAMESPACES ) ) 434 { 435 namespaces = Namespaces.createStandardMappings( root ); 436 Namespaces.buildIndexNode( namespaces ); // index node for faster lookup 437 } 438 else 439 { 440 namespaces = root.getChildNode( NamespaceConstants.REP_NAMESPACES ); 441 } 442 Namespaces.addCustomMapping( namespaces, "http://archiva.apache.org/jcr/", "archiva" ); 443 444 log.info( "Creating index " ); 445 446 NodeBuilder oakIdx = IndexUtils.getOrCreateOakIndex( root ); 447 if (!oakIdx.hasChildNode( "repo-lucene" )) 448 { 449 NodeBuilder lucene = oakIdx.child( "repo-lucene" ); 450 lucene.setProperty( JCR_PRIMARYTYPE, "oak:QueryIndexDefinition", NAME ); 451 452 lucene.setProperty( "compatVersion", 2 ); 453 lucene.setProperty( "type", "lucene" ); 454 // lucene.setProperty("async", "async"); 455 // lucene.setProperty( INCLUDE_PROPERTY_TYPES, ImmutableSet.of( ), Type.STRINGS ); 456 // lucene.setProperty("refresh",true); 457 NodeBuilder rules = lucene.child( "indexRules" ). 458 setProperty( JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME ); 459 rules.setProperty( ":childOrder", ImmutableSet.of( 460 REPOSITORY_NODE_TYPE, 461 NAMESPACE_MIXIN_TYPE, // 462 PROJECT_MIXIN_TYPE, 463 PROJECT_VERSION_NODE_TYPE, // 464 ARTIFACT_NODE_TYPE, // 465 FACET_NODE_TYPE // 466 ), Type.STRINGS ); 467 IndexDefinitionBuilder idxBuilder = new IndexDefinitionBuilder( lucene ); 468 idxBuilder.async( "async", "nrt", "sync" ).includedPaths( "/repositories" ).evaluatePathRestrictions(); 469 470 initBaseRule(idxBuilder.indexRule( REPOSITORY_NODE_TYPE )); 471 initBaseRule(idxBuilder.indexRule(NAMESPACE_MIXIN_TYPE)) 472 .property( "namespace" ).propertyIndex().analyzed(); 473 initBaseRule(idxBuilder.indexRule(PROJECT_MIXIN_TYPE)) 474 .property( "name" ).propertyIndex().analyzed().notNullCheckEnabled().nullCheckEnabled(); 475 initBaseRule( idxBuilder.indexRule( PROJECT_VERSION_NODE_TYPE ) ) 476 .property("name").propertyIndex().analyzed().notNullCheckEnabled().nullCheckEnabled() 477 .property("description").propertyIndex().analyzed().notNullCheckEnabled().nullCheckEnabled() 478 .property("url").propertyIndex().analyzed( ).notNullCheckEnabled().nullCheckEnabled() 479 .property("incomplete").type("Boolean").propertyIndex() 480 .property("mailinglist/name").propertyIndex().analyzed() 481 .property("license/license.name").propertyIndex().analyzed(); 482 initBaseRule(idxBuilder.indexRule( ARTIFACT_NODE_TYPE )) 483 .property( "whenGathered" ).type("Date").propertyIndex().analyzed().ordered() 484 .property("size").type("Long").propertyIndex().analyzed().ordered() 485 .property("version").propertyIndex().analyzed().ordered() 486 .property("checksums/*/value").propertyIndex(); 487 488 initBaseRule( idxBuilder.indexRule( CHECKSUM_NODE_TYPE ) ) 489 .property("type").propertyIndex() 490 .property("value").propertyIndex(); 491 492 initRegexAll( idxBuilder.indexRule( FACET_NODE_TYPE ) ) 493 .property("archiva:facetId").propertyIndex().analyzed().ordered() 494 .property("archiva:name").propertyIndex().analyzed().ordered().nullCheckEnabled().notNullCheckEnabled(); 495 496 idxBuilder.indexRule( MIXIN_META_SCM ) 497 .property( "scm.connection" ).propertyIndex() 498 .property( "scm.developerConnection" ).propertyIndex() 499 .property( "scm.url").type("URI").propertyIndex().analyzed(); 500 idxBuilder.indexRule( MIXIN_META_CI ) 501 .property( "ci.system" ).propertyIndex( ) 502 .property( "ci.ur" ).propertyIndex( ).analyzed( ); 503 idxBuilder.indexRule( MIXIN_META_ISSUE ) 504 .property( "issue.system").propertyIndex() 505 .property("issue.url").propertyIndex().analyzed(); 506 idxBuilder.indexRule( MIXIN_META_ORGANIZATION ) 507 .property( "org.name" ).propertyIndex( ).analyzed( ) 508 .property( "org.url" ).propertyIndex( ).analyzed( ); 509 idxBuilder.indexRule( LICENSE_NODE_TYPE ) 510 .property( "license.name" ).propertyIndex( ).analyzed( ) 511 .property( "license.url" ).propertyIndex( ).analyzed( ); 512 idxBuilder.indexRule( MAILINGLIST_NODE_TYPE ) 513 .property( "name" ).propertyIndex().analyzed(); 514 initBaseRule(idxBuilder.indexRule( DEPENDENCY_NODE_TYPE )) 515 .property( "groupId" ).propertyIndex().analyzed().ordered() 516 .property( "artifactId").propertyIndex().analyzed().ordered() 517 .property("version").propertyIndex().analyzed().ordered() 518 .property("type").propertyIndex().analyzed().ordered() 519 .property( "classifier" ).propertyIndex().ordered() 520 .property("scope").propertyIndex() 521 .property("systemPath").propertyIndex().analyzed() 522 .property("optional").type("Boolean").propertyIndex(); 523 524 idxBuilder.aggregateRule( PROJECT_VERSION_NODE_TYPE ).include( "dependencies") 525 .path("dependencies/*" ).relativeNode(); 526 527 idxBuilder.build( ); 528 529 IndexUtils.createIndexDefinition( oakIdx, "baseIndexes", true, false, ImmutableList.of( "jcr:uuid", "rep:principalName" ), null ); 530 531 log.info( "Index: {} repo-lucene: {}", lucene, lucene.getChildNode( "repo-lucene" ) ); 532 log.info( "repo-lucene Properties: {}", lucene.getChildNode( "repo-lucene" ).getProperties( ) ); 533 } else { 534 log.info( "No Index update" ); 535 } 536 // IndexUtils.createIndexDefinition( ) 537 538 } 539 }; 540 541 // ExternalObserverBuilder builder = new ExternalObserverBuilder(queue, tracker, statsProvider, 542// executorService, queueSize); 543// Observer observer = builder.build(); 544// builder.getBackgroundObserver(); 545 546 547 548 log.info( "Starting Jcr repo with nodeStore {}", nodeStore ); 549 Jcr jcr = new Jcr( nodeStore ).with( editorProvider ) // 550 .with( backgroundObserver ) // 551 .with( externalIndexObserver ) 552 // .with(observer) 553 .with( (QueryIndexProvider) indexProvider ) 554 .with (repoInitializer) 555 .withAsyncIndexing( "async", 5 ); 556 // 557 //.withAsyncIndexing( "async", 5 ); 558 StopWatch stopWatch = new StopWatch(); 559 stopWatch.start(); 560 Repository r = jcr.createRepository(); 561 stopWatch.stop(); 562 log.info( "time to create jcr repository: {} ms", stopWatch.getTime() ); 563 564 return r; 565 566 567 } 568 569 private void closeSilently( Closeable service) { 570 if (service!=null) { 571 try 572 { 573 service.close(); 574 } 575 catch ( Throwable e ) 576 { 577 // 578 } 579 } 580 } 581 582 public void close() 583 { 584 log.info( "Closing JCR RepositoryFactory" ); 585 closeSilently( fileStore ); 586 closeSilently( backgroundObserver ); 587 closeSilently( externalIndexObserver ); 588 closeSilently( indexProvider ); 589 indexProvider = null; 590 closeSilently( documentQueue ); 591 closeSilently( nrtIndexFactory ); 592 closeSilently( indexCopier ); 593 594 if (executorService != null){ 595 executorService.shutdown(); 596 try 597 { 598 executorService.awaitTermination(1, TimeUnit.MINUTES); 599 } 600 catch ( InterruptedException e ) 601 { 602 e.printStackTrace( ); 603 } 604 } 605 606 if (extractedTextCache != null) { 607 extractedTextCache.close(); 608 } 609 610 } 611 612 public StoreType getStoreType() 613 { 614 return storeType; 615 } 616 617 public void setStoreType( StoreType storeType ) 618 { 619 this.storeType = storeType; 620 } 621 622 public Path getRepositoryPath() 623 { 624 return repositoryPath; 625 } 626 627 public void setRepositoryPath( Path repositoryPath ) 628 { 629 this.repositoryPath = repositoryPath; 630 } 631 632 public void setRepositoryPath( String repositoryPath ) 633 { 634 this.repositoryPath = Paths.get( repositoryPath ); 635 if ( !Files.exists( this.repositoryPath ) ) 636 { 637 try 638 { 639 Files.createDirectories( this.repositoryPath ); 640 } 641 catch ( IOException e ) 642 { 643 log.error( e.getMessage(), e ); 644 throw new IllegalArgumentException( "cannot create directory:" + repositoryPath, e ); 645 } 646 } 647 } 648 649 650}