de.ingrid.admin.elasticsearch.IndexScheduler.java Source code

Java tutorial

Introduction

Here is the source code for de.ingrid.admin.elasticsearch.IndexScheduler.java

Source

/*
 * **************************************************-
 * ingrid-base-webapp
 * ==================================================
 * Copyright (C) 2014 - 2018 wemove digital solutions GmbH
 * ==================================================
 * Licensed under the EUPL, Version 1.1 or  as soon they will be
 * approved by the European Commission - subsequent versions of the
 * EUPL (the "Licence");
 * 
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 * 
 * http://ec.europa.eu/idabc/eupl5
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 * **************************************************#
 */
package de.ingrid.admin.elasticsearch;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import de.ingrid.admin.JettyStarter;
import de.ingrid.utils.IConfigurable;
import de.ingrid.utils.PlugDescription;
import it.sauronsoftware.cron4j.Scheduler;
import it.sauronsoftware.cron4j.Task;
import it.sauronsoftware.cron4j.TaskExecutionContext;
import it.sauronsoftware.cron4j.TaskExecutor;

@Service
public class IndexScheduler implements IConfigurable {

    private final Scheduler _scheduler;

    private final IndexRunnable _runnable;

    private String _scheduleId;

    private String _pattern;

    private File _patternFile;

    private static final Log LOG = LogFactory.getLog(IndexScheduler.class);

    private static class LockRunnable extends Task {

        private final Runnable _runnable;

        private static boolean _isRunning = false;

        public LockRunnable(final Runnable runnable) {
            _runnable = runnable;
        }

        @Override
        public void execute(TaskExecutionContext arg0) throws RuntimeException {
            LOG.debug("trying to run index scheduler");
            if (!_isRunning) {
                LOG.info("starting and locking index scheduler");
                _isRunning = true;
                try {
                    _runnable.run();
                } catch (final Throwable t) {
                    LOG.error(t);
                } finally {
                    LOG.info("unlocking index scheduler");
                    _isRunning = false;
                }
            } else {
                LOG.info("index scheduler is still busy");
            }
        }

    }

    @Autowired
    public IndexScheduler(final IndexRunnable runnable) {
        _runnable = runnable;
        _scheduler = new Scheduler();
        if (_runnable.getPlugDescription() != null) {
            configure(_runnable.getPlugDescription());
        }

        // if we want to index on startup we start a new Thread for this, since the
        // other services still need to be configured and we cannot let this thread sleep
        if (JettyStarter.getInstance().config.indexOnStartup) {
            LOG.info("Initial indexing on startup ...");
            new InitialIndexRun().start();
        }
    }

    public void setPattern(final String pattern) {
        _pattern = pattern;
        if (_patternFile != null) {
            savePatternFile();
        }
        schedule();
    }

    public String getPattern() {
        return _pattern;
    }

    public void deletePattern() {
        LOG.debug("delete pattern");
        _pattern = null;
        deletePatternFile();
        if (isStarted()) {
            LOG.info("stop scheduler");
            _scheduler.stop();
        }
    }

    public boolean isStarted() {
        return _scheduler.isStarted();
    }

    @Override
    public void configure(final PlugDescription plugDescription) {
        _patternFile = new File(plugDescription.getWorkinDirectory(), "pattern");
        if (_patternFile.exists()) {
            loadPatternFile();
            schedule();
        }
    }

    private void schedule() {
        if (_pattern == null) {
            LOG.info("No valid pattern found: '" + _pattern + "'");
            return;
        }
        if (_scheduleId == null) {
            LOG.info("scheduling indexer with pattern '" + _pattern + "'");
            _scheduleId = _scheduler.schedule(_pattern, new LockRunnable(_runnable));
        } else {
            LOG.info("rescheduling indexer with pattern '" + _pattern + "'");
            _scheduler.reschedule(_scheduleId, _pattern);
        }
        if (!isStarted()) {
            LOG.info("start scheduler");
            _scheduler.start();
        }
    }

    public boolean isRunning() {
        if (!_scheduler.isStarted()) {
            return false;
        }
        for (TaskExecutor task : _scheduler.getExecutingTasks()) {
            if (task.isAlive()) {
                return true;
            }
        }
        return false;
    }

    public boolean triggerManually() {
        try {
            if (!isRunning()) {
                if (!_scheduler.isStarted()) {
                    _scheduler.start();
                }
                _scheduler.launch(new LockRunnable(_runnable));
                return true;
            }
        } catch (Exception e) {
            LOG.error("Error running task now!", e);
        }
        return false;
    }

    private void loadPatternFile() {
        LOG.debug("try to load pattern from file");
        try {
            final ObjectInputStream reader = new ObjectInputStream(new FileInputStream(_patternFile));
            _pattern = (String) reader.readObject();
            reader.close();
        } catch (final Exception e) {
            LOG.error(e);
        }
    }

    private void savePatternFile() {
        deletePatternFile();
        LOG.debug("saving pattern to file");
        try {

            final ObjectOutputStream writer = new ObjectOutputStream(new FileOutputStream(_patternFile));
            writer.writeObject(_pattern);
            writer.close();
        } catch (final Exception e) {
            LOG.error(e);
        }
    }

    private void deletePatternFile() {
        if (_patternFile != null && _patternFile.exists()) {
            LOG.debug("deleting pattern file");
            _patternFile.delete();
        }
    }

    /**
     * A separate Thread to start an index action on startup.
     * Since some services need to be configured, we have to add a little delay here.
     * @author Andre
     *
     */
    private class InitialIndexRun extends Thread {

        // delay execution in ms
        private int delay = 10000;

        @Override
        public void run() {
            try {
                Thread.sleep(delay);
            } catch (InterruptedException ignored) {
            }
            triggerManually();
        }
    }
}