/* * Copyright (C) 2010 - 2012 Interactive Media Management * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package dk.i2m.converge.jsf.beans; import dk.i2m.converge.core.security.UserAccount; import dk.i2m.converge.domain.search.SearchResult; import dk.i2m.converge.domain.search.SearchResults; import dk.i2m.converge.ejb.facades.SearchEngineLocal; import dk.i2m.jsf.JsfUtils; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.faces.model.DataModel; import javax.faces.model.ListDataModel; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; /** * JSF backing bean for {@code /search.jspx}. * * @author Allan Lykke Christensen */ public class Search { @EJB private SearchEngineLocal searchEngine; private String keyword = ""; private DataModel searchResults = new ListDataModel(); private DataModel pages = new ListDataModel(new ArrayList()); private boolean showResults = false; private long resultsFound = 0; private String sortField = "score"; private String sortOrder = "false"; private String searchType = "type:Story"; private SearchResults results = new SearchResults(); private List<String> filterQueries = new ArrayList<String>(); private Date dateFrom; private Date dateTo; private boolean criteriaDate = false; private boolean criteriaType = true; private long archiveSize = -1; public Search() { } @PostConstruct public void onInit() { reset(); } public long getArchiveSize() { if (archiveSize < 0) { archiveSize = searchEngine.search("*:*", 1, 1).getNumberOfResults(); } return archiveSize; } private void reset() { this.keyword = ""; this.searchResults = new ListDataModel(); this.pages = new ListDataModel(new ArrayList()); this.showResults = false; this.resultsFound = 0; this.sortField = getUser().getDefaultSearchResultsSortBy(); if (this.sortField == null) { this.sortField = "score"; } this.sortOrder = Boolean.toString( getUser().isDefaultSearchResultsOrder()); this.searchType = "type:Story"; this.results = new SearchResults(); this.filterQueries = new ArrayList<String>(); this.dateFrom = null; this.dateTo = null; this.criteriaDate = false; this.criteriaType = true; } public List<String> getFilterQueries() { return filterQueries; } public void setFilterQueries(List<String> filterQueries) { this.filterQueries = filterQueries; } /** * Gets the keyword (query) being searched for. * * @return Keyword (query) being searched for */ public String getKeyword() { return keyword; } /** * Sets the keyword (query) to be searched for. * * @param keyword * Keyword (query) to be searched for */ public void setKeyword(String keyword) { this.keyword = keyword; } /** * Gets the search results. * * @return {@link DataModel} containing the {@link SearchResult}s */ public DataModel getSearchResults() { return searchResults; } /** * Determines if the results should be shown. * * @return {@code true} if the search results should be shown otherwise * {@code false} */ public boolean isShowResults() { return showResults; } public void onGenerateOverview(ActionEvent event) { // Fetch 1000 results max conductSearch(getKeyword(), 0, 1000); byte[] output = searchEngine.generateReport(this.results); String filename = JsfUtils.getResourceBundle(Bundle.i18n.name()).getString( "Search_OVERVIEW_REPORT_FILENAME"); HttpServletResponse response = (HttpServletResponse) FacesContext. getCurrentInstance().getExternalContext().getResponse(); response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-disposition", "attachment; filename=" + filename); try { ServletOutputStream out = response.getOutputStream(); out.write(output); out.flush(); out.close(); } catch (IOException ex) { JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_ERROR, Bundle.i18n.name(), "Search_COULD_NOT_OVERVIEW_GENERATE_REPORT", new Object[]{ex. getMessage()}); } FacesContext faces = FacesContext.getCurrentInstance(); faces.responseComplete(); } /** * Event handler for starting the search. * * @param event Event that invoked the handler */ public void onSearch(ActionEvent event) { if (StringUtils.isEmpty(getKeyword())) { setKeyword("*:*"); } filterQueries = new ArrayList<String>(); conductSearch(keyword, 0, 10); } public void onClear(ActionEvent event) { reset(); } public void onChangePage(ActionEvent event) { String changePage = JsfUtils.getRequestParameterMap().get("changePage"); if (changePage != null) { int newPage = Integer.valueOf(changePage); int newStart = (newPage - 1) * results.getResultsPerPage(); int rows = results.getResultsPerPage(); conductSearch(keyword, newStart, rows); } } public void onAddFacet(ActionEvent event) { String filterQuery = JsfUtils.getRequestParameterMap().get("addFacet"); if (filterQuery != null) { filterQueries.add(filterQuery); conductSearch(keyword, 0, 10); } } public void onRemoveFacet(ActionEvent event) { String filterQuery = JsfUtils.getRequestParameterMap().get("filterQuery"); if (filterQuery != null) { filterQueries.remove(filterQuery); conductSearch(keyword, 0, 10); } } private void conductSearch(String keyword, int start, int rows) { searchResults = new ListDataModel(new ArrayList()); pages = new ListDataModel(new ArrayList()); List<String> filters = new ArrayList<String>(); if (isCriteriaType()) { filters.add(searchType); } filters.addAll(filterQueries); this.results = searchEngine.search(keyword, start, rows, sortField, Boolean.valueOf(sortOrder), getDateFrom(), getDateTo(), filters. toArray(new String[filters.size()])); if (results.getNumberOfResults() == 0) { showResults = false; searchResults = new ListDataModel(new ArrayList()); JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_INFO, Bundle.i18n.name(), "Search_NO_RESULTS_FOUND", new Object[]{getKeyword()}); } else { for (SearchResult hit : results.getHits()) { hit.setLink( MessageFormat.format(hit.getLink(), new Object[]{ JsfUtils.getValueOfValueExpression( "#{facesContext.externalContext.request.contextPath}")})); } searchResults = new ListDataModel(results.getHits()); for (long l = 0; l < results.getNumberOfPages(); l++) { if (l >= 20) { break; } SearchPage page = new SearchPage((l + 1), l * results. getResultsPerPage(), results.getNumberOfPages()); ((ArrayList) getPages().getWrappedData()).add(page); } showResults = true; } } public long getResultsFound() { return resultsFound; } public SearchResults getResults() { return results; } public void setResults(SearchResults results) { this.results = results; } public DataModel getPages() { return pages; } public void setPages(DataModel pages) { this.pages = pages; } public String getSearchType() { return searchType; } public void setSearchType(String searchType) { this.searchType = searchType; } public String getSortField() { return sortField; } public void setSortField(String sortField) { this.sortField = sortField; } public String getSortOrder() { return sortOrder; } public void setSortOrder(String sortOrder) { this.sortOrder = sortOrder; } /** * Gets the {@link Date} for which the search results must not be earlier. * * @return {@link Date} for which the search results must not be earlier */ public Date getDateFrom() { return dateFrom; } /** * Sets the {@link Date} for which the search results must not be earlier. * * @param dateFrom {@link Date} for which the search results must not be * earlier */ public void setDateFrom(Date dateFrom) { this.dateFrom = dateFrom; } /** * Gets the {@link Date} for which the search results must not be older. * * @return {@link Date} for which the search results must not be older */ public Date getDateTo() { return dateTo; } /** * Sets the {@link Date} for which the search results must not be older. * * @param dateTo {@link Date} for which the search results must not be older */ public void setDateTo(Date dateTo) { this.dateTo = dateTo; } public boolean isCriteriaDate() { return criteriaDate; } public void setCriteriaDate(boolean criteriaDate) { this.criteriaDate = criteriaDate; } public boolean isCriteriaType() { return criteriaType; } public void setCriteriaType(boolean criteriaType) { this.criteriaType = criteriaType; } private UserAccount getUser() { return (UserAccount) JsfUtils.getValueOfValueExpression( "#{userSession.user}"); } /** * Event handler for removing an item from the search engine. * * @param searchResult {@link SearchResult} to remove from the search engine */ public void setRemoveItem(SearchResult searchResult) { searchEngine.removeItem(searchResult.getId()); JsfUtils.createMessage("frmPage", FacesMessage.SEVERITY_INFO, "i18n", "Search_REMOVE_CONFIRM", new Object[]{}); } public class SearchPage { private long page = 1; private long start = 0; private long show = 0; public SearchPage(long page, long start, long show) { this.page = page; this.start = start; this.show = show; } public long getPage() { return page; } public void setPage(long page) { this.page = page; } public long getShow() { return show; } public void setShow(long show) { this.show = show; } public long getStart() { return start; } public void setStart(long start) { this.start = start; } } }