Author: bpoussin Date: 2011-08-20 14:14:02 +0200 (Sat, 20 Aug 2011) New Revision: 315 Url: http://chorem.org/repositories/revision/bow/315 Log: Evolution #438: Refactore source code and simplify all - gros refactore de opensearch suggest, prend 25ms au lieu de 9s :D et surtout fonctionne ;) Removed: trunk/bow-ui/src/main/java/org/chorem/bow/OpenSearchActions.java Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BookmarkUtils.java trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java trunk/bow-ui/src/main/java/org/chorem/bow/action/bookmark/HomeAction.java trunk/bow-ui/src/main/java/org/chorem/bow/action/preference/UpdateUserAction.java trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties trunk/bow-ui/src/main/resources/struts.xml Modified: trunk/bow-ui/src/main/java/org/chorem/bow/BookmarkUtils.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/BookmarkUtils.java 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/java/org/chorem/bow/BookmarkUtils.java 2011-08-20 12:14:02 UTC (rev 315) @@ -42,6 +42,11 @@ */ public static Log log = LogFactory.getLog(BookmarkUtils.class); + /** + * Ajoute a la recherche tout ce qui est necessaire pour connaitre + * toutes les informations que l'utilisateur peut voir, meme s'il n'est + * pas le createur de ce bookmark + */ static public Search addEqUser(Search search, String userId) { Search result = search.or(); result = result.eq(BowBookmark.FQ_FIELD_WIKITTYAUTHORISATION_OWNER, userId); Deleted: trunk/bow-ui/src/main/java/org/chorem/bow/OpenSearchActions.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/OpenSearchActions.java 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/java/org/chorem/bow/OpenSearchActions.java 2011-08-20 12:14:02 UTC (rev 315) @@ -1,162 +0,0 @@ -/* - * #%L - * bow - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2010 CodeLutin - * %% - * 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 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/>. - * #L% - */ -package org.chorem.bow; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import org.apache.commons.lang.StringUtils; -import org.nuiton.wikitty.search.FacetTopic; - -/** - * - * @author bbrossaud - */ -public class OpenSearchActions { - - protected List<BowBookmark> bookmarkList = new ArrayList<BowBookmark>(); - protected List<FacetTopic> suggestions = new ArrayList<FacetTopic>(); - protected String[] search; - - public void findSuggestions(Set<String> searchLine) { - int size = searchLine.size(); - search = searchLine.toArray(new String[size]); - String word = search[size - 1]; - List<FacetTopic> save = new ArrayList<FacetTopic>(suggestions); - for (FacetTopic topic : save) { - String tag = topic.getTopicName(); - if (tag != null) { - if (tag.indexOf(word) != 0 || searchLine.contains(tag)) { - suggestions.remove(topic); - } - } - } - List<BowBookmark> cpy = new ArrayList<BowBookmark>(bookmarkList); - for (BowBookmark bookmark : cpy) { - Set<String> tags = bookmark.getLabels(); - boolean delete = true; - for (FacetTopic topic : suggestions) { - String name = topic.getTopicName(); - if (tags != null && tags.contains(name)) { - delete = false; - break; - } - } - if (delete) { - bookmarkList.remove(bookmark); - } - } - Collections.sort(suggestions, new SuggestionsComparator()); - } - - protected boolean bookmarkHasTag(BowBookmark bookmark, String tag) { - Set<String> tagList = bookmark.getLabels(); - if (tagList != null) { - if (tagList.contains(tag)) { - return true; - } - } - return false; - } - - public void setBookmarkList(List<BowBookmark> bookmarks) { - if (bookmarks != null) { - List<BowBookmark> newList = new ArrayList<BowBookmark>(bookmarks); - bookmarkList = newList; - } - } - - public String getJsonResult() { - String str = "["; - - str += "\"" + StringUtils.join(search, ' ') + "\","; - str += getJsonSuggestions(); - str += ","; - str += getJsonDescription(); - str += "]"; - return str; - } - - public String getJsonSuggestions() { - String str = "["; - String srch = ""; - Iterator<FacetTopic> it = suggestions.iterator(); - if (search.length > 1) { - srch = StringUtils.join(search, ' ', 0, search.length - 1); - srch += " "; - } - while (it.hasNext()) { - FacetTopic su = it.next(); - str += "\"" + srch + su.getTopicName() + "\""; - if (it.hasNext()) { - str += ","; - } - } - if (bookmarkList.size() <= 5 && suggestions.size() > 0) { - for (BowBookmark bookmark : bookmarkList) { - str += ",\"" + bookmark.getLink() + "\""; - } - } - str += "]"; - return str; - } - - public String getJsonDescription() { - String str = "["; - Iterator<FacetTopic> it = suggestions.iterator(); - while (it.hasNext()) { - FacetTopic su = it.next(); - str += "\"" + su.getCount() + " results\""; - if (it.hasNext()) { - str += ","; - } - } - str += "]"; - return str; - } - - public void setSearch(String[] tab) { - search = tab; - } - - public void setSuggestionList(List<FacetTopic> list) { - if (list != null) { - suggestions = new ArrayList<FacetTopic>(list); - } - } - - public List<BowBookmark> getBookmarkList() { - return bookmarkList; - } - - public String[] getSearch() { - return search; - } - - public List<FacetTopic> getSuggestionList() { - return suggestions; - } -} Modified: trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/OpenSearchSuggestionAction.java 2011-08-20 12:14:02 UTC (rev 315) @@ -24,9 +24,14 @@ package org.chorem.bow.action; import com.opensymphony.xwork2.ActionContext; +import java.io.InputStream; +import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.commons.lang.StringUtils; +import org.chorem.bow.BookmarkUtils; import org.chorem.bow.BowBookmark; import org.chorem.bow.OpenSearchActions; @@ -36,6 +41,7 @@ import org.nuiton.wikitty.search.FacetTopic; import org.nuiton.wikitty.search.PagedResult; import org.nuiton.wikitty.WikittyProxy; +import org.nuiton.wikitty.entities.Wikitty; import org.nuiton.wikitty.search.Search; /** @@ -53,9 +59,23 @@ return (OpenSearchSuggestionAction) action; } - protected OpenSearchActions openSearchActions; + /** le token utilise pour faire l'appel (permanent ou temporaire) */ + protected String token; protected String searchLine; + protected InputStream inputStream; + public InputStream getInputStream() { + return inputStream; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + public String getSearchLine() { return searchLine; } @@ -64,47 +84,93 @@ this.searchLine = searchLine; } - - public OpenSearchActions getOpenSearchActions() { - return openSearchActions; - } - @Override public String execute() { - BowUser user = getBowSession().getUser(); + if (log.isDebugEnabled()) { + log.debug(String.format("Start opensearch suggest for '%s'", searchLine)); + } + // preparation de la reponse. Un toString sur une liste retourne + // la bonne syntaxe pour une reponse json :) si on triche un peu + // en ajoutant des '' pour les chaines + List json = new ArrayList(); + List<String> completions = new ArrayList<String>(); + List<String> descriptions = new ArrayList<String>(); + List<String> queryUrls = new ArrayList<String>(); + + json.add("'" + searchLine + "'"); + json.add(completions); + json.add(descriptions); + json.add(queryUrls); + if (searchLine != null) { - openSearchActions = new OpenSearchActions(); + BowUser user = getBowSession().getUser(); WikittyProxy proxy = getBowProxy(); - Set<String> searchLineList = BowUtils.getWords(searchLine); + // on ajoute * a la fin du dernier tag, car il n'est peut-etre pas fini + String searchLineStar = searchLine + "*"; + + // on recupere le dernier tag en train d'etre ecrit + String lastTag; + if (searchLine.contains(" ")) { + lastTag = StringUtils.substringAfterLast(searchLine, " "); + } else { + lastTag = searchLine; + } - if (searchLine.charAt(searchLine.length() - 1) == ' ') { - searchLineList.add(""); //If the user doesn't type anything, we have to propose suggestions + Set<String> searchLineList = BowUtils.getWords(searchLineStar); + + Search search = BookmarkUtils.addEqUser(Search.query(), user.getWikittyId()); + search.exteq(BowBookmark.EXT_WIKITTYLABEL); + search.contains(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS, searchLineList); + + Criteria criteria= search + .criteria() + .setEndIndex(0) // on ne veut aucun resultat, c'est la facet dont on a besoin + .setFacetMinCount(1) // on demande meme les labels avec 1 seul item + .setFacetLimit(Integer.MAX_VALUE) // ne ne met pas -1 pour qu'il soit trie par ordre de count + .addFacetField(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); + + PagedResult<Wikitty> result = proxy.findAllByCriteria(criteria); + // lorsqu'on demande tout (facetLimit(-1)), les topics sont trie + // alphabetiquement pas besoin de les retrier + List<FacetTopic> topics = result.getTopic(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); + if (log.isTraceEnabled()) { + log.trace("all topics: %s" + topics); } - Criteria criteria; - if (searchLineList.size() > 1) { - List<String> cpy = new ArrayList<String>(searchLineList); - cpy.remove(cpy.size() - 1); - criteria = Search.query() - .eq(BowBookmark.FQ_FIELD_WIKITTYAUTHORISATION_OWNER, user.getWikittyId()) - // TODO poussin 20110216 eq n'est sans doute pas bon, plutot un contains ? - .eq(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS, cpy).criteria() - .addFacetField(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); - } else { - criteria = Search.query() - .eq(BowBookmark.FQ_FIELD_WIKITTYAUTHORISATION_OWNER, user.getWikittyId()).criteria() - .addFacetField(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); + // on en retourne un suggestion que le meme nombre de tag qu'il souhaite + // voir affiche + int count = user.getTags(); + for(FacetTopic t : topics) { + // on ne met que les topics qui qui commence par lastTag + String completion = t.getTopicName(); + if (log.isTraceEnabled()) { + log.trace(String.format("'%s' startsWith '%s' ? ", completion, lastTag)); + } + if (completion.startsWith(lastTag)) { + String description = _("%s results",t.getCount()); + String queryUrl = String.format("%shome?token=%s&tagLine=%s", + getConfig().getBowUrl(), + token, + searchLine + StringUtils.removeStart(completion, lastTag)); + + completions.add("'" + completion + "'"); + descriptions.add("'" + description + "'"); + queryUrls.add("'" + queryUrl + "'"); + + // on s'arrete si l'on en a assez + count--; + if (count <= 0) { + break; + } + } } - PagedResult<BowBookmark> result = proxy.findAllByCriteria(BowBookmark.class, criteria); - List<BowBookmark> bookList = result.getAll(); - List<FacetTopic> topics = result.getTopic(BowBookmark.FQ_FIELD_WIKITTYLABEL_LABELS); - - openSearchActions.setBookmarkList(bookList); - openSearchActions.setSuggestionList(topics); - openSearchActions.findSuggestions(searchLineList); } + if (log.isDebugEnabled()) { + log.debug(String.format("opensearch suggest result: %s", json)); + } + inputStream = new ReaderInputStream(new StringReader(json.toString())); return SUCCESS; } } \ No newline at end of file Modified: trunk/bow-ui/src/main/java/org/chorem/bow/action/bookmark/HomeAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/bookmark/HomeAction.java 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/bookmark/HomeAction.java 2011-08-20 12:14:02 UTC (rev 315) @@ -24,8 +24,6 @@ package org.chorem.bow.action.bookmark; import com.opensymphony.xwork2.ActionContext; -import java.util.Arrays; -import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; Modified: trunk/bow-ui/src/main/java/org/chorem/bow/action/preference/UpdateUserAction.java =================================================================== --- trunk/bow-ui/src/main/java/org/chorem/bow/action/preference/UpdateUserAction.java 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/java/org/chorem/bow/action/preference/UpdateUserAction.java 2011-08-20 12:14:02 UTC (rev 315) @@ -86,9 +86,10 @@ if (result == SUCCESS) { user = proxy.store(user); getBowSession().setUser(user); - addActionMessage(_("bow.preferences.update.successful")); + addActionMessage(_("bow.preferences.update.successful")); } } catch (Exception eee) { + result = ERROR; addActionError(_("bow.error.internal")); log.error("Can't change site preference", eee); } finally { Modified: trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties =================================================================== --- trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/resources/i18n/bow-ui_en_GB.properties 2011-08-20 12:14:02 UTC (rev 315) @@ -1,3 +1,4 @@ +%s\ results= alias= bow.action.locale.english=English bow.action.locale.french=Fran\u00E7ais Modified: trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties =================================================================== --- trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/resources/i18n/bow-ui_fr_FR.properties 2011-08-20 12:14:02 UTC (rev 315) @@ -1,3 +1,4 @@ +%s\ results= alias= bow.action.locale.english=English bow.action.locale.french=Fran\u00E7ais Modified: trunk/bow-ui/src/main/resources/struts.xml =================================================================== --- trunk/bow-ui/src/main/resources/struts.xml 2011-08-20 12:12:25 UTC (rev 314) +++ trunk/bow-ui/src/main/resources/struts.xml 2011-08-20 12:14:02 UTC (rev 315) @@ -158,7 +158,13 @@ <result type="redirect">${redirectTo}</result> </action> <action name="openSearchSuggestion" class="org.chorem.bow.action.OpenSearchSuggestionAction"> - <result>/jsp/suggestions.jsp</result> +<!-- <result>/jsp/suggestions.jsp</result> --> + <result type="stream"> + <param name="contentType">application/x-suggestions+json</param> + <param name="inputName">inputStream</param> + <param name="contentDisposition">inline</param> + <param name="allowCaching">false</param> + </result> </action> <action name="*Xml"> <result>/jsp/{1}Xml.jsp</result>