fr.gael.dhus.server.http.webapp.search.controller.SearchController.java Source code

Java tutorial

Introduction

Here is the source code for fr.gael.dhus.server.http.webapp.search.controller.SearchController.java

Source

/*
 * Data Hub Service (DHuS) - For Space data distribution.
 * Copyright (C) 2015-2018 GAEL Systems
 *
 * This file is part of DHuS software sources.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package fr.gael.dhus.server.http.webapp.search.controller;

import de.odysseus.staxon.json.JsonXMLConfig;
import de.odysseus.staxon.json.JsonXMLConfigBuilder;
import de.odysseus.staxon.json.JsonXMLOutputFactory;

import fr.gael.dhus.database.object.config.server.ServerConfiguration;
import fr.gael.dhus.search.SolrDao;
import fr.gael.dhus.service.SearchService;
import fr.gael.dhus.system.config.ConfigurationManager;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Principal;
import java.util.List;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class SearchController {
    /**
     * Special value for environment variable `max.product.page.size` to remove the limitation
     * on the value of the `rows` query parameter.
     */
    private static final int UNLIMITED_SEARCH_ROWS = -1;

    private static final Logger LOGGER = LogManager.getLogger();

    /** Maximum value for the `rows` parameter. */
    private final static Integer ROW_LIMIT = Integer.getInteger("max.product.page.size", 100);

    /** OpenSearch standard description file. */
    private final static String DESCRIPTION_FILE = "opensearch-description-file.xml";

    @Autowired
    private ConfigurationManager configurationManager;

    @Autowired
    private SolrDao solrDao;

    @Autowired
    private SearchService searchService;

    @PreAuthorize("hasRole('ROLE_SEARCH')")
    @RequestMapping(value = "/suggest/{query}")
    public void suggestions(@PathVariable String query, HttpServletResponse res) throws IOException {
        List<String> suggestions = searchService.getSuggestions(query);
        res.setStatus(HttpServletResponse.SC_OK);
        res.setContentType("text/plain");
        try (ServletOutputStream outputStream = res.getOutputStream()) {
            for (String suggestion : suggestions) {
                outputStream.println(suggestion);
            }
        }
    }

    /**
     * Provides the openSearch description file via /search/description API.
     *
     * @param res response
     * @throws IOException if file description cannot be accessed
     */
    @PreAuthorize("hasRole('ROLE_SEARCH')")
    @RequestMapping(value = "/description")
    public void search(HttpServletResponse res) throws IOException {
        String url = configurationManager.getServerConfiguration().getExternalUrl();
        if (url != null && url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }

        String long_name = configurationManager.getNameConfiguration().getLongName();
        String short_name = configurationManager.getNameConfiguration().getShortName();
        String contact_mail = configurationManager.getSupportConfiguration().getMail();

        InputStream is = ClassLoader.getSystemResourceAsStream(DESCRIPTION_FILE);
        if (is == null) {
            throw new IOException("Cannot find \"" + DESCRIPTION_FILE + "\" OpenSearch description file.");
        }

        LineIterator li = IOUtils.lineIterator(is, "UTF-8");

        try (ServletOutputStream os = res.getOutputStream()) {
            while (li.hasNext()) {
                String line = li.next();
                // Last line? -> the iterator eats LF
                if (li.hasNext()) {
                    line = line + "\n";
                }

                line = line.replace("[dhus_server]", url);
                if (long_name != null) {
                    line = line.replace("[dhus_long_name]", long_name);
                }
                if (short_name != null) {
                    line = line.replace("[dhus_short_name]", short_name);
                }
                if (contact_mail != null) {
                    line = line.replace("[dhus_contact_mail]", contact_mail);
                }

                os.write(line.getBytes());
            }
        } finally {
            IOUtils.closeQuietly(is);
            LineIterator.closeQuietly(li);
        }
    }

    @PreAuthorize("hasRole('ROLE_SEARCH')")
    @RequestMapping(value = "/")
    public void search(Principal principal, @RequestParam(value = "q") String original_query,
            @RequestParam(value = "rows", defaultValue = "") String rows_str,
            @RequestParam(value = "start", defaultValue = "") String start_str,
            @RequestParam(value = "format", defaultValue = "") String format,
            @RequestParam(value = "orderby", required = false) String orderby, HttpServletResponse res)
            throws IOException, XMLStreamException, SolrServerException {
        ServerConfiguration dhusServer = configurationManager.getServerConfiguration();

        String query = convertQuery(original_query);
        LOGGER.info("Rewritten Query: {}", query);

        boolean json = "json".equalsIgnoreCase(format);

        SolrQuery solrQuery = new SolrQuery(query);
        solrQuery.setParam("wt", "xslt").setParam("tr", "opensearch_atom.xsl")
                .setParam("dhusLongName", configurationManager.getNameConfiguration().getLongName())
                .setParam("dhusServer", dhusServer.getExternalUrl())
                .setParam("type", json ? "application/json" : "application/xml")
                .setParam("originalQuery", original_query);

        if (json) {
            solrQuery.setParam("format", "json");
        }

        if (rows_str != null && !rows_str.isEmpty()) {
            try {
                int rows = Integer.parseInt(rows_str);
                if (ROW_LIMIT != UNLIMITED_SEARCH_ROWS && rows > ROW_LIMIT) {
                    String errorMessage = String
                            .format("Parameter `rows` exceeds the maximum value (%d) in search request", ROW_LIMIT);
                    LOGGER.warn(errorMessage);
                    res.sendError(HttpServletResponse.SC_BAD_REQUEST, errorMessage);
                    return;
                }
                solrQuery.setRows(rows);
            } catch (NumberFormatException nfe) {
                /* noting to do : keep the default value */
            }
        }
        if (start_str != null && !start_str.isEmpty()) {
            try {
                int start = Integer.parseInt(start_str);
                solrQuery.setStart(start);
            } catch (NumberFormatException nfe) {
                /* noting to do : keep the default value */
            }
        }
        // If `orderby` param is not defined, default to ordering by ingestiondate desc.
        // Define `orderby` to `""` (empty string) to order by the full text search score.
        if (orderby == null) {
            solrQuery.setSort("ingestiondate", SolrQuery.ORDER.desc);
        } else if (!orderby.isEmpty()) {
            solrQuery.setParam("sort", orderby.toLowerCase());
        }

        try (InputStream is = solrDao.streamSelect(solrQuery)) {
            try (ServletOutputStream os = res.getOutputStream()) {
                res.setStatus(HttpServletResponse.SC_OK);
                if ("json".equalsIgnoreCase(format)) {
                    res.setContentType("application/json");
                    xmlToJson(is, os);
                } else {
                    res.setContentType("application/xml");
                    IOUtils.copy(is, os);
                }
            }
        } catch (Exception e) {
            res.addHeader("cause-message", String.format("%s : %s", e.getClass().getSimpleName(), e.getMessage()));
            throw e;
        }
    }

    private String convertQuery(String query) {
        return solrDao.updateQuery(query);
    }

    void xmlToJson(InputStream xmlInput, OutputStream jsonOutput) throws XMLStreamException {
        JsonXMLConfig config = new JsonXMLConfigBuilder().autoArray(true).autoPrimitive(false).fieldPrefix("")
                .contentField("content").build();

        XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(xmlInput);
        XMLEventWriter writer = new JsonXMLOutputFactory(config).createXMLEventWriter(jsonOutput);

        writer.add(reader);

        reader.close();
        writer.close();
    }
}