All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bazoud.elasticsearch.river.git.GitRiver Maven / Gradle / Ivy

package com.bazoud.elasticsearch.river.git;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtilsBean2;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.indices.IndexAlreadyExistsException;
import org.elasticsearch.river.AbstractRiverComponent;
import org.elasticsearch.river.River;
import org.elasticsearch.river.RiverIndexName;
import org.elasticsearch.river.RiverName;
import org.elasticsearch.river.RiverSettings;

import com.bazoud.elasticsearch.river.git.beans.Context;
import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;

/**
 * @author Olivier Bazoud
 */
public class GitRiver extends AbstractRiverComponent implements River {
    private Client client;
    private volatile Thread indexerThread;
    private volatile boolean closed;
    @Inject
    private FunctionFlowFactory functionFlowFactory;

    private Context context = new Context();

    @Inject
    protected GitRiver(RiverName riverName, RiverSettings settings, @RiverIndexName String riverIndexName, Client client) throws InvocationTargetException, IllegalAccessException {
        super(riverName, settings);
        this.client = client;
        logger.info("Creating Git river");

        if (settings.settings().containsKey("git")) {
            Map gitSettings = (Map) settings.settings().get("git");
            BeanUtilsBean2.getInstance().populate(context, transformKeys(gitSettings, new Function() {
                @Override
                public String apply(String input) {
                    return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, input);
                }
            }));
        }
        context.setRiverName(riverName.name());
        context.setRiverIndexName(riverIndexName);
        context.setClient(client);
        context.setIssuePattern(compilePattern(context.getIssueRegex()));
    }

    @Override
    public void start() {
        logger.info("Starting Git River: name '{}', uri '{}', updateRate '{}', indexing to '{}'/'{}'",
            context.getName(), context.getUri(), context.getUpdateRate(), context.getRiverName(), context.getType());

        try {
            client.admin().cluster().prepareHealth()
                .setWaitForYellowStatus()
                .execute().actionGet();

            client.admin().indices().prepareCreate(context.getRiverName()).execute().actionGet();
            logger.info("Index '{}'/'{}' created", context.getRiverName(), context.getType());

        } catch (Exception e) {
            if (ExceptionsHelper.unwrapCause(e) instanceof IndexAlreadyExistsException) {
                // that's fine
            } else if (ExceptionsHelper.unwrapCause(e) instanceof ClusterBlockException) {
                // ok, not recovered yet..., lets start indexing and hope we recover by the first bulk
            } else {
                logger.warn("failed to create index '{}', disabling river...", e, context.getRiverName());
                return;
            }
        }

        indexerThread = EsExecutors.daemonThreadFactory(settings.globalSettings(), "git_river_indexer").newThread(new GitIndexer());
        indexerThread.start();
    }

    @Override
    public void close() {
        if (closed) {
            return;
        }
        logger.info("Stopping Git River");
        indexerThread.interrupt();
        closed = true;
    }

    private Optional compilePattern(String regex) {
        Optional issuePattern = Optional.absent();
        try {
            issuePattern = Optional.of(Pattern.compile(regex));
        } catch (Throwable e) {
            logger.warn("Git river exception occurred when parsing regex |{}|", issuePattern, e);
        }
        return issuePattern;
    }

    /**
     * @author Olivier Bazoud
     */
    public class GitIndexer implements Runnable {

        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            while (true) {
                if (closed) {
                    return;
                }

                try {
                    functionFlowFactory
                        .create()
                        .apply(context);

                } catch (Exception e) {
                    logger.warn("Git river exception occurred", e);
                }

                try {
                    logger.debug("Git river is going to sleep for {} ms", context.getUpdateRate());
                    Thread.sleep(context.getUpdateRate());
                } catch (InterruptedException e) {
                    // we shamefully swallow the interrupted exception
                    logger.warn("Git river interrupted");
                }
            }
        }

    }

    public static  ImmutableMap transformKeys(
        Map map, Function keyFunction) {
        ImmutableMap.Builder builder = ImmutableMap.builder();
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            K key = iterator.next();
            builder.put(keyFunction.apply(key), map.get(key));
        }
        return builder.build();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy