This project has retired. For details please refer to its Attic page.
Source code
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}