org.jabylon.index.properties.jobs.impl.ReorgIndexJob.java Source code

Java tutorial

Introduction

Here is the source code for org.jabylon.index.properties.jobs.impl.ReorgIndexJob.java

Source

/**
 * (C) Copyright 2013 Jabylon (http://www.jabylon.org) and others.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
/**
 *
 */
package org.jabylon.index.properties.jobs.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.net4j.CDONet4jSession;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.jabylon.cdo.connector.RepositoryConnector;
import org.jabylon.cdo.server.ServerConstants;
import org.jabylon.index.properties.IndexActivator;
import org.jabylon.index.properties.impl.PropertyFileAnalyzer;
import org.jabylon.properties.Project;
import org.jabylon.properties.PropertyFile;
import org.jabylon.properties.PropertyFileDescriptor;
import org.jabylon.properties.Workspace;
import org.jabylon.properties.types.impl.TMXConverter;
import org.jabylon.scheduler.JobExecution;
import org.jabylon.scheduler.JobUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Johannes Utzig (jutzig.dev@googlemail.com)
 *
 */
@Component(enabled = true, immediate = true)
@Service
public class ReorgIndexJob implements JobExecution {

    public static final String JOB_ID = "job.reorg.index";

    private static final Logger logger = LoggerFactory.getLogger(ReorgIndexJob.class);

    @org.apache.felix.scr.annotations.Property(value = "true", name = JobExecution.PROP_JOB_ACTIVE)
    public static final String DEFAULT_ACTIVE = "true";

    /** at 2 am every day*/
    @org.apache.felix.scr.annotations.Property(value = "0 0 2 * * ?", name = JobExecution.PROP_JOB_SCHEDULE)
    public static final String DEFAULT_SCHEDULE = "0 0 2 * * ?";

    @org.apache.felix.scr.annotations.Property(value = "%reorg.job.name", name = JobExecution.PROP_JOB_NAME)
    private String NAME = JobExecution.PROP_JOB_NAME;

    /** at 2 am every day*/
    @org.apache.felix.scr.annotations.Property(value = "%reorg.job.description", name = JobExecution.PROP_JOB_DESCRIPTION)
    private String DESCRIPTION = JobExecution.PROP_JOB_DESCRIPTION;

    /**
     *
     */
    public ReorgIndexJob() {
    }

    @Override
    public void run(IProgressMonitor monitor, Map<String, Object> jobContext) throws Exception {
        RepositoryConnector connector = JobUtil.getRepositoryConnector(jobContext);
        indexWorkspace(connector, monitor);
    }

    @Override
    public boolean retryOnError() {
        // retry if the index is currently locked
        return true;
    }

    private static void indexWorkspace(Workspace workspace, IndexWriter writer, IProgressMonitor monitor)
            throws CorruptIndexException, IOException {
        EList<Project> projects = workspace.getChildren();
        SubMonitor submon = SubMonitor.convert(monitor, "Rebuilding Index", projects.size() * 10);
        PropertyFileAnalyzer analyzer = new PropertyFileAnalyzer();
        try {
            for (Project project : projects) {
                SubMonitor mon = submon.newChild(10, 0);
                mon.beginTask("", 100); //TODO that is not exactly accurate, but at least it moves :-)
                String message = "Indexing {0}";
                submon.setTaskName(MessageFormat.format(message, project.getName()));
                TreeIterator<EObject> contents = project.eAllContents();
                while (contents.hasNext()) {
                    checkCanceled(monitor);
                    EObject next = contents.next();
                    if (next instanceof PropertyFileDescriptor) {
                        PropertyFileDescriptor descriptor = (PropertyFileDescriptor) next;
                        mon.subTask(descriptor.getLocation().toString());
                        List<Document> documents = analyzer.createDocuments(descriptor);
                        for (Document document : documents) {
                            writer.addDocument(document);
                        }
                        mon.worked(1);
                    }
                }
                mon.done();
            }
        } finally {
            monitor.done();
        }
    }

    /**
     * analyzes the TMX directory
     * @param writer
     * @param monitor
     */
    private static void indexTMX(IndexWriter writer, IProgressMonitor monitor) {
        PropertyFileAnalyzer analyzer = new PropertyFileAnalyzer();
        File workingDir = new File(ServerConstants.WORKING_DIR);
        File tmx = new File(workingDir, "tmx");
        File[] files = tmx.listFiles();
        if (files == null)
            return;
        for (File file : files) {

            TMXConverter converter = new TMXConverter();
            try {
                PropertyFile propertyFile = converter.load(new FileInputStream(file), "UTF-8");
                List<Document> documents = analyzer.createTMXDocuments(propertyFile,
                        URI.createFileURI("tmx/" + file.getName()));
                for (Document document : documents) {
                    writer.addDocument(document);
                }

            } catch (FileNotFoundException e) {
                logger.error("Could not load TMX file", e);
            } catch (IOException e) {
                logger.error("Could not load TMX file", e);
            }
        }

    }

    private static void checkCanceled(IProgressMonitor monitor) {
        if (monitor.isCanceled())
            throw new OperationCanceledException();

    }

    public static void indexWorkspace(RepositoryConnector connector, IProgressMonitor monitor)
            throws CorruptIndexException, IOException {
        long time = System.currentTimeMillis();
        logger.info("Reorg of search index started");
        IndexWriter writer = null;
        CDONet4jSession session = null;
        SubMonitor submon = SubMonitor.convert(monitor, 100);
        try {
            writer = IndexActivator.getDefault().obtainIndexWriter();
            writer.deleteAll();
            session = connector.createSession();
            CDOView view = connector.openView(session);
            CDOResource resource = view.getResource(ServerConstants.WORKSPACE_RESOURCE);
            Workspace workspace = (Workspace) resource.getContents().get(0);
            indexWorkspace(workspace, writer, submon.newChild(95));
            indexTMX(writer, submon.newChild(5));
            writer.commit();
        } catch (OutOfMemoryError error) {
            logger.error("Out of memory during index reorg", error);
            //As suggested by lucene documentation
            writer.close();
        } catch (Exception e) {
            logger.error("Exception during index reorg. Rolling back", e);
            if (writer != null)
                writer.rollback();
            throw new IllegalStateException("Failed to write index", e);
        } finally {
            if (monitor != null)
                monitor.done();
            if (session != null) {
                session.close();
            }
            IndexActivator.getDefault().returnIndexWriter(writer);
        }
        long duration = (System.currentTimeMillis() - time) / 1000;
        logger.info("Search Index Reorg finished. Took {} seconds", duration);
    }

    @Override
    public String getID() {
        return JOB_ID;
    }
}