com.searchbox.framework.web.SearchboxController.java Source code

Java tutorial

Introduction

Here is the source code for com.searchbox.framework.web.SearchboxController.java

Source

/**
 * *****************************************************************************
 * Copyright Searchbox - http://www.searchbox.com
 *
 * Licensed 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 com.searchbox.framework.web;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;

import com.searchbox.core.SearchCollector;
import com.searchbox.core.SearchElement;
import com.searchbox.core.dm.Collection;
import com.searchbox.core.dm.FieldAttribute;
import com.searchbox.core.dm.SearchableCollection;
import com.searchbox.core.engine.SearchEngine;
import com.searchbox.core.search.AbstractSearchCondition;
import com.searchbox.core.search.RetryElement;
import com.searchbox.framework.model.FieldAttributeEntity;
import com.searchbox.framework.model.PresetEntity;
import com.searchbox.framework.model.SearchConditionEntity;
import com.searchbox.framework.model.SearchboxEntity;
import com.searchbox.framework.model.UserEntity;
import com.searchbox.framework.model.UserFavoriteEntity;
import com.searchbox.framework.repository.PresetRepository;
import com.searchbox.framework.repository.SearchboxRepository;
import com.searchbox.framework.service.SearchElementService;
import com.searchbox.framework.service.SearchService;
import com.searchbox.framework.service.UserFavoriteService;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

@Controller
@RequestMapping("/{searchbox}")
@Order(value = 10000000)
@Transactional
public class SearchboxController {

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

    @ModelAttribute("user")
    public UserEntity getUser(@AuthenticationPrincipal UserEntity user) {
        return user;
    }

    private List<String> favorites;

    @Autowired
    ApplicationConversionService conversionService;

    @Autowired
    SearchService searchService;

    @Autowired
    SearchboxRepository searchboxRepository;

    @Autowired
    protected PresetRepository presetRepository;

    @Autowired
    protected SearchElementService elementService;

    @Autowired
    private UserFavoriteService service;

    public SearchboxController() {
    }

    protected String getViewFolder() {
        return "search";
    }

    @ModelAttribute("searchboxes")
    public List<SearchboxEntity> getAllSearchboxes() {
        ArrayList<SearchboxEntity> searchboxes = new ArrayList<SearchboxEntity>();
        Iterator<SearchboxEntity> sbx = searchboxRepository.findAll().iterator();
        while (sbx.hasNext()) {
            searchboxes.add(sbx.next());
        }
        return searchboxes;
    }

    @ModelAttribute("presets")
    public List<PresetEntity> getAllPresets(@PathVariable SearchboxEntity searchbox) {
        return presetRepository.findAllBySearchboxAndVisibleOrderByPositionAsc(searchbox, true);
    }

    @ModelAttribute("conditions")
    public Set<AbstractSearchCondition> getSearchConditions(HttpServletRequest request) {
        // Fetch all search Conditions within HTTP params
        Set<AbstractSearchCondition> conditions = new HashSet<AbstractSearchCondition>();
        for (String param : conversionService.getSearchConditionParams()) {
            if (request.getParameterValues(param) != null) {
                LOGGER.info("Parsing condition {} from params", param);
                for (String value : request.getParameterValues(param)) {
                    if (value != null && !value.isEmpty()) {
                        try {
                            AbstractSearchCondition cond = (AbstractSearchCondition) conversionService
                                    .convert(value, conversionService.getSearchConditionClass(param));
                            conditions.add(cond);
                        } catch (Exception e) {
                            LOGGER.error("Could not convert " + value, e);
                        }
                    }
                }
            }
        }
        return conditions;
    }

    @ModelAttribute("collector")
    public SearchCollector getSearchCollector() {
        return new SearchCollector();
    }

    @RequestMapping(value = { "", "/" })
    @ResponseBody
    public ModelAndView getHome(@PathVariable SearchboxEntity searchbox, HttpServletRequest request,
            ModelAndView model, RedirectAttributes redirectAttributes) {
        model.setViewName(this.getViewFolder() + "/home");

        if (searchbox == null) {
            LOGGER.error("Searchbox {} not found!", searchbox);
            return new ModelAndView(new RedirectView("/", true));
        }

        PresetEntity preset = searchbox.getPresets().first();
        LOGGER.info("No Preset, redirect to: {}", preset.getSlug());
        ModelAndView redirect = new ModelAndView(
                new RedirectView("/" + searchbox.getSlug() + "/" + preset.getSlug(), true));
        return redirect;
    }

    @RequestMapping(value = { "/{preset}", "/{preset}/" })
    public ModelAndView getDefaultPreset(@PathVariable SearchboxEntity searchbox, HttpServletRequest request,
            @PathVariable PresetEntity preset, ModelAndView model, RedirectAttributes redirectAttributes) {

        if (preset == null) {
            LOGGER.error("Preset {} not found!", preset);
            return getHome(searchbox, request, model, redirectAttributes);

        }
        String process = preset.getDefaultProcess();
        LOGGER.info("Missing process. Redirecting to default process of preset: {}", process);
        ModelAndView redirect = new ModelAndView(
                new RedirectView("/" + searchbox.getSlug() + "/" + preset.getSlug() + "/" + process, true));
        return redirect;

    }

    @RequestMapping(value = { "/{preset}/{process}", "/{preset}/{process}/" })
    public ModelAndView executeSearch(@PathVariable String process,
            @ModelAttribute("searchboxes") List<SearchboxEntity> searchboxes,
            @PathVariable SearchboxEntity searchbox, @PathVariable PresetEntity preset,
            @ModelAttribute("collector") SearchCollector collector,
            @ModelAttribute("conditions") Set<AbstractSearchCondition> conditions, ModelAndView model,
            RedirectAttributes redirectAttributes) {

        if (searchbox == null) {
            LOGGER.error("Searchbox {} not found!", searchbox);
            return new ModelAndView(new RedirectView("/", true));
        }
        LOGGER.info("search page for: {} with preset: {} and process: {}", searchbox.getName(), preset.getLabel(),
                process);
        //refresh favorite
        favorites = getFavorites();

        // TODO check if we have a view for that process.
        model.setViewName(this.getViewFolder() + "/" + process);
        LOGGER.info("exView:" + this.getViewFolder() + "/" + process);
        Set<SearchElement> resultElements = executeRequest(searchbox, preset, process, conditions, collector);

        model.addObject("preset", preset);
        model.addObject("process", process);
        model.addObject("elements", resultElements);
        model.addObject("collector", collector);

        model.addObject("favorites", favorites);
        return model;
    }

    @RequestMapping(headers = {
            "Accept=application/json" }, value = "/{preset}/{process}", method = RequestMethod.GET)
    public ModelAndView executeJsonSearch(@PathVariable String process,
            @ModelAttribute("searchboxes") List<SearchboxEntity> searchboxes,
            @PathVariable SearchboxEntity searchbox, @PathVariable PresetEntity preset,
            @ModelAttribute("collector") SearchCollector collector,
            @ModelAttribute("conditions") Set<AbstractSearchCondition> conditions, ModelAndView model,
            RedirectAttributes redirectAttributes) {

        LOGGER.info("JSON Search");
        LOGGER.debug("search page for: {} with preset: {} and process: {}", searchbox, preset, process);

        // TODO check if we have a view for that process.
        model.setViewName(this.getViewFolder() + "/" + process);
        LOGGER.info("JSON View:" + this.getViewFolder() + "/" + process);
        //TODO: Make the JSON view- http://www.javablog.fr/javaspringjson-generate-json-withwithout-viewresolver-jsonview-with-json-lib-2-3-jdk15.html
        Set<SearchElement> resultElements = executeRequest(searchbox, preset, process, conditions, collector);

        model.addObject("preset", preset);
        model.addObject("process", process);
        model.addObject("elements", resultElements);
        model.addObject("collector", collector);

        return model;
    }

    private Set<FieldAttribute> getAllFieldAttribute(PresetEntity preset) {

        Set<FieldAttribute> fieldAttributes = new HashSet<>();
        for (FieldAttributeEntity def : preset.getFieldAttributes(true)) {
            fieldAttributes.add(def.build());
        }

        return fieldAttributes;
    }

    private Set<AbstractSearchCondition> getAllSearchConditions(PresetEntity preset) {
        Set<AbstractSearchCondition> fieldAttributes = new HashSet<>();
        for (SearchConditionEntity<?> def : preset.getSearchConditions(true)) {
            LOGGER.info("Got Search Condition entity: {}", def);
            fieldAttributes.add(def.build());

        }
        return fieldAttributes;
    }

    protected Set<SearchElement> executeRequest(SearchboxEntity searchbox, PresetEntity preset, String process,
            Set<AbstractSearchCondition> conditions, SearchCollector collector) {

        Set<SearchElement> searchElements = elementService.getSearchElements(preset, process);
        LOGGER.debug("Required Search elements are {}", searchElements);

        Set<FieldAttribute> fieldAttributes = getAllFieldAttribute(preset);

        Set<AbstractSearchCondition> presetConditions = getAllSearchConditions(preset);
        LOGGER.info("Required preset Conditions are {}", presetConditions);

        Collection collection = preset.getCollection().build();

        if (!(SearchableCollection.class.isAssignableFrom(collection.getClass()))) {
            LOGGER.error("Collection {} does NOT implement SearchableCollection!!!", collection.getName());
        }

        SearchEngine<?, ?> searchEngine = ((SearchableCollection) collection).getSearchEngine();

        LOGGER.debug("Current SearchEngine: {}", searchEngine);
        LOGGER.debug("Current Collection: {}", collection);
        LOGGER.debug("presetConditions: {}" + presetConditions);
        LOGGER.debug("conditions: {}" + conditions);
        Set<SearchElement> resultElements = searchService.execute(searchEngine, collection, searchElements,
                fieldAttributes, presetConditions, conditions, collector);
        LOGGER.debug("Resulting SearchElements are {}", resultElements);

        // Check if we have a retry clause
        boolean retry = false;
        for (SearchElement element : resultElements) {
            if (RetryElement.class.isAssignableFrom(element.getClass())) {
                if (((RetryElement) element).shouldRetry()) {
                    LOGGER.debug("RetryElement:" + element.getLabel());
                    retry = true;
                }
            }
        }

        if (retry) {
            LOGGER.debug("Start retry");
            LOGGER.debug("Current SearchEngine: {}", searchEngine);
            LOGGER.debug("Current Collection: {}", collection);

            resultElements = searchService.execute(searchEngine, collection, searchElements, fieldAttributes,
                    presetConditions, conditions, collector);
        }
        return resultElements;
    }

    public List<String> getFavorites() {
        List<String> param = new ArrayList();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof AnonymousAuthenticationToken)) {
            UserEntity user = (UserEntity) authentication.getPrincipal();
            List<UserFavoriteEntity> list = service.findFavoriteByUserId(user);
            for (int i = 0; i < list.size(); i++) {
                UserFavoriteEntity u = list.get(i);
                String uid = u.getFavoriteId();
                param.add(uid);
            }

        }
        return param;
    }

}