org.eclipse.orion.internal.server.search.SearchActivator.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.orion.internal.server.search.SearchActivator.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2012 IBM Corporation 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
 * 
 * Contributors:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.orion.internal.server.search;

import java.io.*;
import java.net.*;
import javax.servlet.http.HttpServletRequest;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.*;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.orion.internal.server.core.*;
import org.eclipse.orion.internal.server.servlets.ProtocolConstants;
import org.eclipse.orion.server.core.LogHelper;
import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.framework.*;

public class SearchActivator implements BundleActivator, IWebResourceDecorator {
    private static BundleContext context;
    /**
     * Indicates the version number of the Orion search index. This
     * version should be incremented whenever there are breaking changes to the
     * indexing schema or format.
     */
    private static final int CURRENT_INDEX_GENERATION = 15;

    private static final String INDEX_GENERATION_FILE = "index.generation";//$NON-NLS-1$
    private static SearchActivator instance;
    public static final String PI_SEARCH = "org.eclipse.orion.server.core.search"; //$NON-NLS-1$
    /**
     * A family for all jobs related to indexing. Used to join jobs on shutdown.
     */
    public static final Object JOB_FAMILY = new Object();
    private Indexer indexer;
    private IndexPurgeJob purgeJob;
    private ServiceRegistration<IWebResourceDecorator> searchDecoratorRegistration;
    private SolrServer server;
    private SolrCore solrCore;
    private CoreContainer solrContainer;

    static BundleContext getContext() {
        return context;
    }

    public static SearchActivator getInstance() {
        return instance;
    }

    public SearchActivator() {
        super();
        instance = this;
    }

    public void addAtributesFor(HttpServletRequest request, URI resource, JSONObject representation) {
        String service = request.getServletPath();
        if (!("/file".equals(service) || "/workspace".equals(service))) //$NON-NLS-1$ //$NON-NLS-2$
            return;
        try {
            // we can also augment with a query argument that includes the resource path
            URI result = new URI(resource.getScheme(), resource.getAuthority(), "/filesearch", "q=", null); //$NON-NLS-1$//$NON-NLS-2$
            representation.put(ProtocolConstants.KEY_SEARCH_LOCATION, result);
        } catch (URISyntaxException e) {
            LogHelper.log(e);
        } catch (JSONException e) {
            // key and value are well-formed strings so this should not happen
            throw new RuntimeException(e);
        }
    }

    /**
     * Creates and returns a search server instance. Returns null if there was a
     * failure instantiating the server.
     */
    private void createServer() {
        try {
            File rootFile = Activator.getDefault().getPlatformLocation().toFile();
            File baseDir = new File(rootFile, ".metadata/.plugins/" + PI_SEARCH); //$NON-NLS-1$
            // discard all server data if the index generation has changed
            if (readIndexGeneration(baseDir) != CURRENT_INDEX_GENERATION) {
                delete(baseDir);
                writeIndexGeneration(baseDir);
            }
            createSolrConfig(baseDir);
            String solrDataDir = baseDir.toString();
            solrContainer = new CoreContainer(solrDataDir);
            CoreDescriptor descriptor = new CoreDescriptor(solrContainer, "Eclipse Web Search", solrDataDir); //$NON-NLS-1$
            descriptor.setDataDir(solrDataDir.toString() + File.separatorChar + "data"); //$NON-NLS-1$
            solrCore = solrContainer.create(descriptor);
            solrContainer.register(solrCore, false);
            server = new EmbeddedSolrServer(solrContainer, "Eclipse Web Search"); //$NON-NLS-1$
        } catch (Exception e) {
            LogHelper.log(e);
        }
    }

    /**
     * Ensure solr configuration files exist. Copy them from the search plugin
     * if necessary. Returns the solrconfig.xml file.
     */
    private File createSolrConfig(File baseDir) throws FileNotFoundException, IOException {
        File configDir = new File(baseDir, "conf"); //$NON-NLS-1$
        configDir.mkdirs();
        File configFile = new File(configDir, "solrconfig.xml"); //$NON-NLS-1$
        createSolrFile(configFile);
        createSolrFile(new File(configDir, "schema.xml")); //$NON-NLS-1$
        createSolrFile(new File(configDir, "synonyms.txt")); //$NON-NLS-1$
        createSolrFile(new File(configDir, "stopwords.txt")); //$NON-NLS-1$
        createSolrFile(new File(configDir, "protwords.txt")); //$NON-NLS-1$
        createSolrFile(new File(configDir, "elevate.xml")); //$NON-NLS-1$
        return configFile;

    }

    /**
     * Create a configuration file expected by solr (either solrconfig.xml or
     * schema.xml).
     * 
     * @throws IOException
     * @throws FileNotFoundException
     */
    private void createSolrFile(File solrFile) throws FileNotFoundException, IOException {
        if (solrFile.exists())
            return;
        URL source = getClass().getClassLoader().getResource("solrconf/" + solrFile.getName()); //$NON-NLS-1$
        source = FileLocator.resolve(source);
        IOUtilities.pipe(source.openStream(), new FileOutputStream(solrFile), true, true);
    }

    private void delete(File baseDir) {
        try {
            EFS.getStore(baseDir.toURI()).delete(EFS.NONE, null);
        } catch (CoreException e) {
            LogHelper.log(e);
        }
    }

    SolrServer getSolrServer() {
        return server;
    }

    SolrCore getSolrCore() {
        return solrCore;
    }

    /**
     * Returns the generation number of the current index on disk.
     * 
     * @return the current index generation, or -1 if no index was found.
     */
    private int readIndexGeneration(File baseDir) {
        File generationFile = new File(baseDir, INDEX_GENERATION_FILE);
        if (!generationFile.exists())
            return -1;
        DataInputStream in = null;
        try {
            in = new DataInputStream(new FileInputStream(generationFile));
            int generation = Integer.valueOf(in.readUTF());
            return generation;
        } catch (Exception e) {
            // ignore and return false below
        } finally {
            IOUtilities.safeClose(in);
        }
        return -1;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
     * )
     */
    public void start(BundleContext bundleContext) throws Exception {
        SearchActivator.context = bundleContext;
        createServer();
        if (server != null) {
            indexer = new Indexer(server);
            indexer.schedule();

            purgeJob = new IndexPurgeJob(server);
            purgeJob.schedule();
        }
        searchDecoratorRegistration = context.registerService(IWebResourceDecorator.class, this, null);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext bundleContext) throws Exception {
        searchDecoratorRegistration.unregister();
        if (solrContainer != null) {
            solrContainer.shutdown();
            solrContainer = null;
        }
        if (indexer != null) {
            indexer.cancel();
            indexer = null;
        }
        if (purgeJob != null) {
            purgeJob.cancel();
            purgeJob = null;
        }
        //wait for all indexing jobs to complete
        Job.getJobManager().join(JOB_FAMILY, null);
        SearchActivator.context = null;
    }

    private void writeIndexGeneration(File baseDir) {
        baseDir.mkdirs();
        File generationFile = new File(baseDir, INDEX_GENERATION_FILE);
        DataOutputStream out = null;
        try {
            out = new DataOutputStream(new FileOutputStream(generationFile));
            out.writeUTF(Integer.toString(CURRENT_INDEX_GENERATION));
        } catch (IOException e) {
            String msg = "Error writing search index generation number. Subsequent restarts will discard and rebuild search index from scratch"; //$NON-NLS-1$
            LogHelper.log(new Status(IStatus.ERROR, SearchActivator.PI_SEARCH, msg, e));
        } finally {
            IOUtilities.safeClose(out);
        }
    }

    /**
     * Helper method for test suites. This method will block until the next indexer run completes.
     */
    public void testWaitForIndex() {
        try {
            //cancel to wake up a sleeping indexer
            indexer.cancel();
            indexer.schedule();
            indexer.join();
        } catch (InterruptedException e) {
            //just return
        }
    }

}