This project has retired. For details please refer to its Attic page.
OakRepositoryFactory xref
View Javadoc
1   package org.apache.archiva.metadata.repository.jcr;
2   
3   /*
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
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
20   */
21  
22  import com.google.common.collect.ImmutableList;
23  import com.google.common.collect.ImmutableSet;
24  import org.apache.commons.lang3.time.StopWatch;
25  import org.apache.jackrabbit.oak.api.Type;
26  import org.apache.jackrabbit.oak.jcr.Jcr;
27  import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
28  import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoServiceImpl;
29  import org.apache.jackrabbit.oak.plugins.index.IndexInfoProvider;
30  import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
31  import org.apache.jackrabbit.oak.plugins.index.IndexPathServiceImpl;
32  import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
33  import org.apache.jackrabbit.oak.plugins.index.aggregate.SimpleNodeAggregator;
34  import org.apache.jackrabbit.oak.plugins.index.lucene.IndexAugmentorFactory;
35  import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
36  import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
37  import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
38  import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexInfoProvider;
39  import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProvider;
40  import org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory;
41  import org.apache.jackrabbit.oak.plugins.index.lucene.directory.BufferedOakDirectory;
42  import org.apache.jackrabbit.oak.plugins.index.lucene.directory.LuceneIndexImporter;
43  import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.DocumentQueue;
44  import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.ExternalObserverBuilder;
45  import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.LocalIndexObserver;
46  import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.NRTIndexFactory;
47  import org.apache.jackrabbit.oak.plugins.index.lucene.property.PropertyIndexCleaner;
48  import org.apache.jackrabbit.oak.plugins.index.lucene.reader.DefaultIndexReaderFactory;
49  import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
50  import org.apache.jackrabbit.oak.plugins.index.lucene.score.impl.ScorerProviderFactoryImpl;
51  import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
52  import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
53  import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
54  import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
55  import org.apache.jackrabbit.oak.plugins.name.Namespaces;
56  import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
57  import org.apache.jackrabbit.oak.segment.file.FileStore;
58  import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
59  import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
60  import org.apache.jackrabbit.oak.spi.blob.FileBlobStore;
61  import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
62  import org.apache.jackrabbit.oak.spi.commit.BackgroundObserver;
63  import org.apache.jackrabbit.oak.spi.commit.Observer;
64  import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
65  import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
66  import org.apache.jackrabbit.oak.spi.mount.Mounts;
67  import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
68  import org.apache.jackrabbit.oak.spi.query.QueryIndex;
69  import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
70  import org.apache.jackrabbit.oak.spi.state.Clusterable;
71  import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
72  import org.apache.jackrabbit.oak.spi.state.NodeStore;
73  import org.apache.jackrabbit.oak.stats.StatisticsProvider;
74  import org.jetbrains.annotations.NotNull;
75  import org.slf4j.Logger;
76  import org.slf4j.LoggerFactory;
77  
78  import javax.jcr.Repository;
79  import java.io.Closeable;
80  import java.io.IOException;
81  import java.nio.file.Files;
82  import java.nio.file.Path;
83  import java.nio.file.Paths;
84  import java.util.concurrent.ExecutorService;
85  import java.util.concurrent.LinkedBlockingQueue;
86  import java.util.concurrent.ThreadFactory;
87  import java.util.concurrent.ThreadPoolExecutor;
88  import java.util.concurrent.TimeUnit;
89  import java.util.concurrent.atomic.AtomicInteger;
90  
91  import static com.google.common.base.Preconditions.checkNotNull;
92  import static org.apache.archiva.metadata.repository.jcr.JcrConstants.*;
93  import static org.apache.archiva.metadata.repository.jcr.OakRepositoryFactory.StoreType.IN_MEMORY_TYPE;
94  import static org.apache.archiva.metadata.repository.jcr.OakRepositoryFactory.StoreType.SEGMENT_FILE_TYPE;
95  import static org.apache.commons.io.FileUtils.ONE_MB;
96  import static org.apache.jackrabbit.JcrConstants.*;
97  import static org.apache.jackrabbit.oak.api.Type.NAME;
98  
99  /**
100  * Created by martin on 14.06.17.
101  *
102  * @author Martin Stockhammer
103  * @since 3.0.0
104  */
105 public 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 }