Java tutorial
/** * Constellio, Open Source Enterprise Search * Copyright (C) 2010 DocuLibre inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package com.doculibre.constellio.wicket.pages; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.apache.commons.collections.map.ListOrderedMap; import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.RequestCycle; import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupStream; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import com.doculibre.constellio.entities.ConstellioUser; import com.doculibre.constellio.entities.FeaturedLink; import com.doculibre.constellio.entities.IndexField; import com.doculibre.constellio.entities.RecordCollection; import com.doculibre.constellio.entities.search.SimpleSearch; import com.doculibre.constellio.plugins.PluginFactory; import com.doculibre.constellio.plugins.api.wicket.PageFactoryPlugin; import com.doculibre.constellio.services.FeaturedLinkServices; import com.doculibre.constellio.services.IndexFieldServices; import com.doculibre.constellio.services.RecordCollectionServices; import com.doculibre.constellio.services.StatsServices; import com.doculibre.constellio.services.SynonymServices; import com.doculibre.constellio.spellchecker.SpellChecker; import com.doculibre.constellio.utils.ConstellioSpringUtils; import com.doculibre.constellio.utils.NumberFormatUtils; import com.doculibre.constellio.utils.SimpleParams; import com.doculibre.constellio.wicket.application.ConstellioApplication; import com.doculibre.constellio.wicket.data.SearchResultsDataProvider; import com.doculibre.constellio.wicket.panels.facets.FacetsPanel; import com.doculibre.constellio.wicket.panels.header.BaseSearchResultsPageHeaderPanel; import com.doculibre.constellio.wicket.panels.results.SearchResultsPanel; import com.doculibre.constellio.wicket.panels.search.SearchFormPanel; import com.doculibre.constellio.wicket.panels.spellchecker.SpellCheckerPanel; import com.doculibre.constellio.wicket.panels.thesaurus.ThesaurusSuggestionPanel; import com.doculibre.constellio.wicket.session.ConstellioSession; import com.doculibre.constellio.wicket.utils.SimpleParamsUtils; import com.ibm.icu.text.DecimalFormat; @SuppressWarnings("serial") public class SearchResultsPage extends BaseSearchPage { private SearchResultsPanel searchResultsPanel; private SearchResultsDataProvider dataProvider; public SearchResultsPage(PageParameters params) { super(parse(params), params); initComponents(); } public static PageParameters getParameters(SimpleSearch simpleSearch) { SimpleParams simpleParams = simpleSearch.toSimpleParams(false); PageParameters pageParameters = SimpleParamsUtils.toPageParameters(simpleParams); return pageParameters; } public static SimpleSearch parse(PageParameters pageParams) { return parse(pageParams, true); } public static SimpleSearch parse(PageParameters pageParams, boolean searchAllIfEmpty) { SimpleParams simpleParams = SimpleParamsUtils.toSimpleParams(pageParams); SimpleSearch simpleSearch = SimpleSearch.toSimpleSearch(simpleParams); if (StringUtils.isBlank(simpleSearch.getLuceneQuery(false))) { boolean searchAll; if (!searchAllIfEmpty) { String queryParam = pageParams.getString("query"); searchAll = queryParam != null; } else { searchAll = true; } if (searchAll) { simpleSearch.setQuery(SimpleSearch.SEARCH_ALL); } } return simpleSearch; } @Override protected void onBeforeRender() { SimpleSearch simpleSearch = getSimpleSearch(); if (StringUtils.isEmpty(simpleSearch.getCollectionName())) { setResponsePage(ConstellioApplication.get().getHomePage()); } else { super.onBeforeRender(); ConstellioSession.get().addSearchHistory(simpleSearch); QueryResponse queryResponse = dataProvider.getQueryResponse(); if (queryResponse != null) { StatsServices statsServices = ConstellioSpringUtils.getStatsServices(); if (!statsServices.isIgnored(simpleSearch)) { String ipAddress = getWebRequestCycle().getWebRequest().getHttpServletRequest().getRemoteAddr(); String searchLogDocId = statsServices.logSearch(simpleSearch, queryResponse, ipAddress); simpleSearch.setSearchLogDocId(searchLogDocId); } } } } private void initComponents() { final SimpleSearch simpleSearch = getSimpleSearch(); String collectionName = simpleSearch.getCollectionName(); ConstellioUser currentUser = ConstellioSession.get().getUser(); RecordCollectionServices recordCollectionServices = ConstellioSpringUtils.getRecordCollectionServices(); RecordCollection collection = recordCollectionServices.get(collectionName); boolean userHasPermission = false; if (collection != null) { userHasPermission = (!collection.hasSearchPermission()) || (currentUser != null && currentUser.hasSearchPermission(collection)); } if (StringUtils.isEmpty(collectionName) || !userHasPermission) { setResponsePage(ConstellioApplication.get().getHomePage()); } else { final IModel suggestedSearchKeyListModel = new LoadableDetachableModel() { @Override protected Object load() { ListOrderedMap suggestedSearch = new ListOrderedMap(); if (simpleSearch.isQueryValid() && simpleSearch.getQuery() != null) { SpellChecker spellChecker = new SpellChecker(ConstellioApplication.get().getDictionaries()); try { if (!simpleSearch.getQuery().equals("*:*")) { suggestedSearch = spellChecker.suggest(simpleSearch.getQuery(), simpleSearch.getCollectionName()); } } catch (RuntimeException e) { e.printStackTrace(); // chec du spellchecker, pas besoin de faire planter la page } } return suggestedSearch; } }; BaseSearchResultsPageHeaderPanel headerPanel = (BaseSearchResultsPageHeaderPanel) getHeaderComponent(); headerPanel.setAdvancedForm(simpleSearch.getAdvancedSearchRule() != null); SearchFormPanel searchFormPanel = headerPanel.getSearchFormPanel(); final ThesaurusSuggestionPanel thesaurusSuggestionPanel = new ThesaurusSuggestionPanel( "thesaurusSuggestion", simpleSearch, getLocale()); add(thesaurusSuggestionPanel); SpellCheckerPanel spellCheckerPanel = new SpellCheckerPanel("spellChecker", searchFormPanel.getSearchTxtField(), searchFormPanel.getSearchButton(), suggestedSearchKeyListModel) { @SuppressWarnings("unchecked") public boolean isVisible() { boolean visible = false; if (dataProvider != null && !thesaurusSuggestionPanel.isVisible()) { RecordCollectionServices collectionServices = ConstellioSpringUtils .getRecordCollectionServices(); RecordCollection collection = collectionServices.get(simpleSearch.getCollectionName()); if (collection != null && collection.isSpellCheckerActive() && simpleSearch.getAdvancedSearchRule() == null) { ListOrderedMap spell = (ListOrderedMap) suggestedSearchKeyListModel.getObject(); if (spell.size() > 0/* && dataProvider.size() == 0 */) { for (String key : (List<String>) spell.keyList()) { if (spell.get(key) != null) { return visible = true; } } } } } return visible; } }; add(spellCheckerPanel); dataProvider = new SearchResultsDataProvider(simpleSearch, 10); WebMarkupContainer searchResultsSection = new WebMarkupContainer("searchResultsSection") { @Override public boolean isVisible() { return StringUtils.isNotBlank(simpleSearch.getLuceneQuery()); } }; add(searchResultsSection); IModel detailsLabelModel = new LoadableDetachableModel() { @Override protected Object load() { String detailsLabel; QueryResponse queryResponse = dataProvider.getQueryResponse(); long start; long nbRes; double elapsedTimeSeconds; if (queryResponse != null) { start = queryResponse.getResults().getStart(); nbRes = dataProvider.size(); elapsedTimeSeconds = (double) queryResponse.getElapsedTime() / 1000; } else { start = 0; nbRes = 0; elapsedTimeSeconds = 0; } long end = start + 10; if (nbRes < end) { end = nbRes; } String pattern = "#.####"; DecimalFormat elapsedTimeFormatter = new DecimalFormat(pattern); String elapsedTimeStr = elapsedTimeFormatter.format(elapsedTimeSeconds); String forTxt = new StringResourceModel("for", SearchResultsPage.this, null).getString(); String noResultTxt = new StringResourceModel("noResult", SearchResultsPage.this, null) .getString(); String resultsTxt = new StringResourceModel("results", SearchResultsPage.this, null) .getString(); String ofTxt = new StringResourceModel("of", SearchResultsPage.this, null).getString(); String secondsTxt = new StringResourceModel("seconds", SearchResultsPage.this, null) .getString(); String queryTxt = " "; if (simpleSearch.isQueryValid() && simpleSearch.getQuery() != null && simpleSearch.getAdvancedSearchRule() == null) { queryTxt = " " + forTxt + " " + simpleSearch.getQuery() + " "; } if (nbRes > 0) { Locale locale = getLocale(); detailsLabel = resultsTxt + " " + NumberFormatUtils.format(start + 1, locale) + " - " + NumberFormatUtils.format(end, locale) + " " + ofTxt + " " + NumberFormatUtils.format(nbRes, locale) + queryTxt + "(" + elapsedTimeStr + " " + secondsTxt + ")"; } else { detailsLabel = noResultTxt + " " + queryTxt + "(" + elapsedTimeStr + " " + secondsTxt + ")"; } String collectionName = dataProvider.getSimpleSearch().getCollectionName(); if (collectionName != null) { RecordCollectionServices collectionServices = ConstellioSpringUtils .getRecordCollectionServices(); RecordCollection collection = collectionServices.get(collectionName); Locale displayLocale = collection.getDisplayLocale(getLocale()); String collectionTitle = collection.getTitle(displayLocale); detailsLabel = collectionTitle + " > " + detailsLabel; } return detailsLabel; } }; Label detailsLabel = new Label("detailsRes", detailsLabelModel); add(detailsLabel); final IModel sortOptionsModel = new LoadableDetachableModel() { @Override protected Object load() { List<SortChoice> choices = new ArrayList<SortChoice>(); choices.add(new SortChoice(null, null, null)); String collectionName = dataProvider.getSimpleSearch().getCollectionName(); if (collectionName != null) { IndexFieldServices indexFieldServices = ConstellioSpringUtils.getIndexFieldServices(); RecordCollectionServices collectionServices = ConstellioSpringUtils .getRecordCollectionServices(); RecordCollection collection = collectionServices.get(collectionName); for (IndexField indexField : indexFieldServices.getSortableIndexFields(collection)) { String label = indexField.getLabel(IndexField.LABEL_TITLE, ConstellioSession.get().getLocale()); if (label == null || label.isEmpty()) { label = indexField.getName(); } choices.add(new SortChoice(indexField.getName(), label, "asc")); choices.add(new SortChoice(indexField.getName(), label, "desc")); } } return choices; } }; IChoiceRenderer triChoiceRenderer = new ChoiceRenderer() { @Override public Object getDisplayValue(Object object) { SortChoice choice = (SortChoice) object; String displayValue; if (choice.title == null) { displayValue = new StringResourceModel("sort.relevance", SearchResultsPage.this, null) .getString(); } else { String order = new StringResourceModel("sortOrder." + choice.order, SearchResultsPage.this, null).getString(); displayValue = choice.title + " " + order; } return displayValue; } }; IModel value = new Model(new SortChoice(simpleSearch.getSortField(), simpleSearch.getSortField(), simpleSearch.getSortOrder())); DropDownChoice sortField = new DropDownChoice("sortField", value, sortOptionsModel, triChoiceRenderer) { @Override protected boolean wantOnSelectionChangedNotifications() { return true; } @Override protected void onSelectionChanged(Object newSelection) { SortChoice choice = (SortChoice) newSelection; if (choice.name == null) { simpleSearch.setSortField(null); simpleSearch.setSortOrder(null); } else { simpleSearch.setSortField(choice.name); simpleSearch.setSortOrder(choice.order); } simpleSearch.setPage(0); PageFactoryPlugin pageFactoryPlugin = PluginFactory.getPlugin(PageFactoryPlugin.class); RequestCycle.get().setResponsePage(pageFactoryPlugin.getSearchResultsPage(), SearchResultsPage.getParameters(simpleSearch)); } @Override public boolean isVisible() { return ((List<?>) sortOptionsModel.getObject()).size() > 1; } }; searchResultsSection.add(sortField); sortField.setNullValid(false); add(new AjaxLazyLoadPanel("facetsPanel") { @Override public Component getLazyLoadComponent(String markupId) { return new FacetsPanel(markupId, dataProvider); } }); final IModel featuredLinkModel = new LoadableDetachableModel() { @Override protected Object load() { FeaturedLink suggestion; RecordCollectionServices collectionServices = ConstellioSpringUtils .getRecordCollectionServices(); FeaturedLinkServices featuredLinkServices = ConstellioSpringUtils.getFeaturedLinkServices(); Long featuredLinkId = simpleSearch.getFeaturedLinkId(); if (featuredLinkId != null) { suggestion = featuredLinkServices.get(featuredLinkId); } else { String collectionName = simpleSearch.getCollectionName(); if (simpleSearch.getAdvancedSearchRule() == null) { String text = simpleSearch.getQuery(); RecordCollection collection = collectionServices.get(collectionName); suggestion = featuredLinkServices.suggest(text, collection); if (suggestion == null) { SynonymServices synonymServices = ConstellioSpringUtils.getSynonymServices(); List<String> synonyms = synonymServices.getSynonyms(text, collectionName); if (!synonyms.isEmpty()) { for (String synonym : synonyms) { if (!synonym.equals(text)) { suggestion = featuredLinkServices.suggest(synonym, collection); } if (suggestion != null) { break; } } } } } else { suggestion = new FeaturedLink(); } } return suggestion; } }; IModel featuredLinkTitleModel = new LoadableDetachableModel() { @Override protected Object load() { FeaturedLink featuredLink = (FeaturedLink) featuredLinkModel.getObject(); return featuredLink.getTitle(getLocale()); } }; final IModel featuredLinkDescriptionModel = new LoadableDetachableModel() { @Override protected Object load() { FeaturedLink featuredLink = (FeaturedLink) featuredLinkModel.getObject(); StringBuffer descriptionSB = new StringBuffer(); String description = featuredLink.getDescription(getLocale()); if (description != null) { descriptionSB.append(description); String lookFor = "${"; int indexOfLookFor = -1; while ((indexOfLookFor = descriptionSB.indexOf(lookFor)) != -1) { int indexOfEnclosingQuote = descriptionSB.indexOf("}", indexOfLookFor); String featuredLinkIdStr = descriptionSB.substring(indexOfLookFor + lookFor.length(), indexOfEnclosingQuote); int indexOfTagBodyStart = descriptionSB.indexOf(">", indexOfEnclosingQuote) + 1; int indexOfTagBodyEnd = descriptionSB.indexOf("</a>", indexOfTagBodyStart); String capsuleQuery = descriptionSB.substring(indexOfTagBodyStart, indexOfTagBodyEnd); if (capsuleQuery.indexOf("<br/>") != -1) { capsuleQuery = StringUtils.remove(capsuleQuery, "<br/>"); } if (capsuleQuery.indexOf("<br />") != -1) { capsuleQuery = StringUtils.remove(capsuleQuery, "<br />"); } try { String linkedCapsuleURL = getFeaturedLinkURL(new Long(featuredLinkIdStr)); descriptionSB.replace(indexOfLookFor, indexOfEnclosingQuote + 1, linkedCapsuleURL); } catch (NumberFormatException e) { // Ignore } } } return descriptionSB.toString(); } private String getFeaturedLinkURL(Long featuredLinkId) { SimpleSearch clone = simpleSearch.clone(); clone.setFeaturedLinkId(featuredLinkId); PageFactoryPlugin pageFactoryPlugin = PluginFactory.getPlugin(PageFactoryPlugin.class); String url = RequestCycle.get() .urlFor(pageFactoryPlugin.getSearchResultsPage(), getParameters(clone)).toString(); return url; } }; WebMarkupContainer featuredLink = new WebMarkupContainer("featuredLink", featuredLinkModel) { @Override public boolean isVisible() { boolean visible = super.isVisible(); if (visible) { if (featuredLinkModel.getObject() != null) { String description = (String) featuredLinkDescriptionModel.getObject(); visible = StringUtils.isNotEmpty(description); } else { visible = false; } } DataView dataView = (DataView) searchResultsPanel.getDataView(); return visible && dataView.getCurrentPage() == 0; } }; searchResultsSection.add(featuredLink); featuredLink.add(new Label("title", featuredLinkTitleModel)); featuredLink.add(new WebMarkupContainer("description", featuredLinkDescriptionModel) { @Override protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) { String descriptionHTML = (String) getModel().getObject(); replaceComponentTagBody(markupStream, openTag, descriptionHTML); } }); searchResultsSection .add(searchResultsPanel = new SearchResultsPanel("resultatsRecherchePanel", dataProvider)); } } public SearchResultsPanel getSearchResultsPanel() { return searchResultsPanel; } private static class SortChoice implements Serializable { public SortChoice(String name, String title, String order) { super(); this.name = name; this.title = title; this.order = order; } private String name; private String title; private String order; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((order == null) ? 0 : order.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SortChoice other = (SortChoice) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (order == null) { if (other.order != null) return false; } else if (!order.equals(other.order)) return false; return true; } } }