org.xwiki.search.solr.internal.job.IndexerJob.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.search.solr.internal.job.IndexerJob.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.search.solr.internal.job;

import java.util.Arrays;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang3.tuple.Pair;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.annotation.InstantiationStrategy;
import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
import org.xwiki.job.AbstractJob;
import org.xwiki.job.DefaultJobStatus;
import org.xwiki.job.GroupedJob;
import org.xwiki.job.JobGroupPath;
import org.xwiki.job.Request;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.search.solr.internal.api.SolrIndexer;
import org.xwiki.search.solr.internal.job.DiffDocumentIterator.Action;

/**
 * Provide progress information and store logging of an advanced indexing.
 * 
 * @version $Id: 1153d57d4e424c30169dd33eadf2dffbe0bb7eaa $
 * @since 5.1RC1
 */
@Component
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
@Named(IndexerJob.JOBTYPE)
public class IndexerJob extends AbstractJob<IndexerRequest, DefaultJobStatus<IndexerRequest>>
        implements GroupedJob {
    /**
     * The id of the job.
     */
    public static final String JOBTYPE = "solr.indexer";

    /**
     * All indexers run in the same thread.
     */
    // TODO: group indexers based on the IndexerRequest root entity
    private static final JobGroupPath GROUP = new JobGroupPath(Arrays.asList("solr", "indexer"));

    /**
     * Used to send documents to index or delete to/from Solr index.
     */
    @Inject
    private transient SolrIndexer indexer;

    @Inject
    @Named("database")
    private transient DocumentIterator<String> databaseIterator;

    @Inject
    @Named("solr")
    private transient DocumentIterator<String> solrIterator;

    @Override
    public String getType() {
        return JOBTYPE;
    }

    @Override
    public JobGroupPath getGroupPath() {
        return GROUP;
    }

    @Override
    protected IndexerRequest castRequest(Request request) {
        IndexerRequest indexerRequest;
        if (request instanceof IndexerRequest) {
            indexerRequest = (IndexerRequest) request;
        } else {
            indexerRequest = new IndexerRequest(request);
        }

        return indexerRequest;
    }

    @Override
    protected void runInternal() throws Exception {
        if (getRequest().isOverwrite()) {
            EntityReference rootReference = getRequest().getRootReference();
            this.logger.info("Index documents in [{}].", rootReference);
            this.indexer.index(rootReference, true);
        } else {
            updateSolrIndex();
        }
    }

    /**
     * Update the Solr index to match the current state of the database.
     */
    private void updateSolrIndex() {
        DiffDocumentIterator<String> iterator = new DiffDocumentIterator<>(this.solrIterator,
                this.databaseIterator);
        iterator.setRootReference(getRequest().getRootReference());

        this.progressManager.pushLevelProgress(2, this);

        try {
            // Calculate index progress size

            this.progressManager.startStep(this);
            int progressSize = (int) iterator.size();
            this.progressManager.endStep(this);

            // Index

            this.progressManager.startStep(this);
            updateSolrIndex(progressSize, iterator);
            this.progressManager.endStep(this);
        } finally {
            this.progressManager.popLevelProgress(this);
        }
    }

    private void updateSolrIndex(int progressSize, DiffDocumentIterator<String> iterator) {
        this.progressManager.pushLevelProgress(progressSize, this);

        try {
            long[] counter = new long[Action.values().length];

            while (iterator.hasNext()) {
                this.progressManager.startStep(this);

                Pair<DocumentReference, Action> entry = iterator.next();
                if (entry.getValue() == Action.ADD || entry.getValue() == Action.UPDATE) {
                    // The database entry has not been indexed or the indexed version doesn't match the latest
                    // version
                    // from the database.
                    this.indexer.index(entry.getKey(), true);
                } else if (entry.getValue() == Action.DELETE && getRequest().isRemoveMissing()) {
                    // The index entry doesn't exist anymore in the database.
                    this.indexer.delete(entry.getKey(), true);
                }

                counter[entry.getValue().ordinal()]++;

                this.progressManager.endStep(this);
            }

            this.logger.info(
                    "{} documents added, {} deleted and {} updated during the synchronization of the Solr index.",
                    counter[Action.ADD.ordinal()], counter[Action.DELETE.ordinal()],
                    counter[Action.UPDATE.ordinal()]);
        } finally {
            this.progressManager.popLevelProgress(this);
        }
    }
}