org.sakaiproject.nakamura.solr.EmbeddedSolrClient.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.nakamura.solr.EmbeddedSolrClient.java

Source

/**
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.sakaiproject.nakamura.solr;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.NakamuraSolrConfig;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.schema.IndexSchema;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.sakaiproject.nakamura.api.solr.SolrClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

@Component(immediate = true, metatype = true)
@Service(value = SolrClient.class)
public class EmbeddedSolrClient implements SolrClient {

    @Property(value = SolrClient.EMBEDDED)
    public static final String CLIENT_NAME = SolrClient.CLIENT_NAME;

    private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddedSolrClient.class);

    private static final String LOGGER_KEY = "org.sakaiproject.nakamura.logger";
    private static final String LOGGER_VAL = "org.apache.solr";
    /**
     * According to the doc, this is thread safe and must be shared between all
     * threads.
     */
    private EmbeddedSolrServer server;
    private String solrHome;
    private CoreContainer coreContainer;
    private SolrCore nakamuraCore;

    @Property(value = "solrconfig.xml")
    private static final String PROP_SOLR_CONFIG = "solrconfig";
    @Property(value = "schema.xml")
    private static final String PROP_SOLR_SCHEMA = "solrschema";

    @Reference
    protected ConfigurationAdmin configurationAdmin;

    private boolean enabled;

    private Dictionary<String, Object> properties;

    private SolrClientListener listener;

    @SuppressWarnings("unchecked")
    @Activate
    public void activate(ComponentContext componentContext)
            throws IOException, ParserConfigurationException, SAXException {
        BundleContext bundleContext = componentContext.getBundleContext();
        solrHome = Utils.getSolrHome(bundleContext);
        properties = componentContext.getProperties();
    }

    public void enable(SolrClientListener listener) throws IOException, ParserConfigurationException, SAXException {
        if (enabled) {
            return;
        }
        String schemaLocation = Utils.toString(properties.get(PROP_SOLR_SCHEMA), "schema.xml");
        String configLocation = Utils.toString(properties.get(PROP_SOLR_CONFIG), "solrconfig.xml");
        // Note that the following property could be set through JVM level
        // arguments too
        LOGGER.debug("Logger for Embedded Solr is in {slinghome}/log/solr.log at level INFO");
        Configuration logConfiguration = getLogConfiguration();

        // create a log configuration if none was found. leave alone any found
        // configurations
        // so that modifications will persist between server restarts
        if (logConfiguration == null) {
            logConfiguration = configurationAdmin
                    .createFactoryConfiguration("org.apache.sling.commons.log.LogManager.factory.config", null);
            Dictionary<String, Object> loggingProperties = new Hashtable<String, Object>();
            loggingProperties.put("org.apache.sling.commons.log.level", "INFO");
            loggingProperties.put("org.apache.sling.commons.log.file", "logs/solr.log");
            loggingProperties.put("org.apache.sling.commons.log.names", "org.apache.solr");
            // add this property to give us something unique to re-find this
            // configuration
            loggingProperties.put(LOGGER_KEY, LOGGER_VAL);
            logConfiguration.update(loggingProperties);
        }

        System.setProperty("solr.solr.home", solrHome);
        File solrHomeFile = new File(solrHome);
        File coreDir = new File(solrHomeFile, "nakamura");
        // File coreConfigDir = new File(solrHomeFile,"conf");
        deployFile(solrHomeFile, "solr.xml");
        // deployFile(coreConfigDir,"solrconfig.xml");
        // deployFile(coreConfigDir,"schema.xml");
        ClassLoader contextClassloader = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
        ClosableInputSource schemaSource = null;
        ClosableInputSource configSource = null;
        try {
            NakamuraSolrResourceLoader loader = new NakamuraSolrResourceLoader(solrHome,
                    this.getClass().getClassLoader());
            coreContainer = new CoreContainer(loader);
            configSource = getSource(configLocation);
            schemaSource = getSource(schemaLocation);
            LOGGER.info("Configuring with Config {} schema {} ", configLocation, schemaLocation);
            SolrConfig config = new NakamuraSolrConfig(loader, configLocation, configSource);
            IndexSchema schema = new IndexSchema(config, schemaLocation, schemaSource);
            CoreDescriptor coreDescriptor = new CoreDescriptor(coreContainer, "nakamura",
                    coreDir.getAbsolutePath() + "nakamura");
            nakamuraCore = new SolrCore("nakamura", coreDir.getAbsolutePath(), config, schema, coreDescriptor);
            coreContainer.register("nakamura", nakamuraCore, false);
            server = new EmbeddedSolrServer(coreContainer, "nakamura");
            LoggerFactory.getLogger(this.getClass()).info("Contans cores {} ", coreContainer.getCoreNames());
            this.enabled = true;
            this.listener = listener;

        } finally {
            Thread.currentThread().setContextClassLoader(contextClassloader);
            safeClose(schemaSource);
            safeClose(configSource);
        }

    }

    private void safeClose(ClosableInputSource source) {
        if (source != null) {
            try {
                source.close();
            } catch (IOException e) {
                LOGGER.debug(e.getMessage(), e);
            }
        }
    }

    private Configuration getLogConfiguration() throws IOException {
        Configuration logConfiguration = null;
        try {
            Configuration[] configs = configurationAdmin
                    .listConfigurations("(" + LOGGER_KEY + "=" + LOGGER_VAL + ")");
            if (configs != null && configs.length > 0) {
                logConfiguration = configs[0];
            }
        } catch (InvalidSyntaxException e) {
            // ignore this as we'll create what we need
        }
        return logConfiguration;
    }

    private ClosableInputSource getSource(String name) throws IOException {
        if (name.contains(":")) {
            // try a URL
            try {
                URL u = new URL(name);
                InputStream in = u.openStream();
                if (in != null) {

                    return new ClosableInputSource(in);
                }
            } catch (IOException e) {
                LOGGER.debug(e.getMessage(), e);
            }
        }
        // try a file
        File f = new File(name);
        if (f.exists()) {
            return new ClosableInputSource(new FileInputStream(f));
        } else {
            // try classpath
            InputStream in = this.getClass().getClassLoader().getResourceAsStream(name);
            if (in == null) {
                LOGGER.error("Failed to locate stream {}, tried URL, filesystem ", name);
                throw new IOException("Failed to locate stream " + name + ", tried URL, filesystem ");
            }
            return new ClosableInputSource(in);
        }
    }

    private void deployFile(File destDir, String target) throws IOException {
        if (!destDir.isDirectory()) {
            if (!destDir.mkdirs()) {
                LOGGER.warn("Unable to create dest dir {} for {}, may cause later problems ", destDir, target);
            }
        }
        File destFile = new File(destDir, target);
        if (!destFile.exists()) {
            InputStream in = Utils.class.getClassLoader().getResourceAsStream(target);
            OutputStream out = new FileOutputStream(destFile);
            IOUtils.copy(in, out);
            out.close();
            in.close();
        }
    }

    @Deactivate
    public void deactivate(ComponentContext componentContext) {
        disable();
    }

    public void disable() {
        if (!enabled) {
            return;
        }
        nakamuraCore.close();
        coreContainer.shutdown();
        enabled = false;
        if (listener != null) {
            listener.disabled();
        }

    }

    public SolrServer getServer() {
        return server;
    }

    public SolrServer getUpdateServer() {
        return server;
    }

    public String getSolrHome() {
        return solrHome;
    }

    public String getName() {
        return EMBEDDED;
    }

}