/* * ConcourseConnect * Copyright 2009 Concursive Corporation * http://www.concursive.com * * This file is part of ConcourseConnect, an open source social business * software and community platform. * * Concursive ConcourseConnect 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, version 3 of the License. * * Under the terms of the GNU Affero General Public License you must release the * complete source code for any application that uses any part of ConcourseConnect * (system header files and libraries used by the operating system are excluded). * These terms must be included in any work that has ConcourseConnect components. * If you are developing and distributing open source applications under the * GNU Affero General Public License, then you are free to use ConcourseConnect * under the GNU Affero General Public License. * * If you are deploying a web site in which users interact with any portion of * ConcourseConnect over a network, the complete source code changes must be made * available. For example, include a link to the source archive directly from * your web site. * * For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their * products, and do not license and distribute their source code under the GNU * Affero General Public License, Concursive provides a flexible commercial * license. * * To anyone in doubt, we recommend the commercial license. Our commercial license * is competitively priced and will eliminate any confusion about how * ConcourseConnect can be used and distributed. * * ConcourseConnect 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 ConcourseConnect. If not, see <http://www.gnu.org/licenses/>. * * Attribution Notice: ConcourseConnect is an Original Work of software created * by Concursive Corporation */ package com.concursive.connect.web.modules.search.beans; import com.concursive.commons.db.DatabaseUtils; import com.concursive.commons.text.StringUtils; import com.concursive.commons.web.mvc.beans.GenericBean; import com.concursive.connect.web.modules.search.utils.SearchUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** * Contains the properties of a search form * * @author matt rajkowski * @version $Id$ * @created May 17, 2004 */ public class SearchBean extends GenericBean { private static Log LOG = LogFactory.getLog(SearchBean.class); public final static int UNDEFINED = -1; // constant scopes public final static int ALL = 1; public final static int THIS = 2; // constant sections public final static int NEWS = 3; public final static int DISCUSSION = 4; public final static int DOCUMENTS = 5; public final static int LISTS = 6; public final static int PLAN = 7; public final static int TICKETS = 8; public final static int DETAILS = 9; public final static int WIKI = 10; public final static int WEBSITE = 11; public final static int ADS = 12; public final static int CLASSIFIEDS = 13; public final static int REVIEWS = 14; // filters public final static int BEST_MATCH = -1; public final static int HIGHEST_RATED = 1; public final static int MOST_REVIEWED = 2; public final static int NEWLY_ADDED = 3; public final static int NEARBY = 4; public final static int MOST_POPULAR = 5; // search form private String query = null; private String type = null; private int scope = UNDEFINED; private int section = UNDEFINED; private int projectId = -1; private boolean openProjectsOnly = false; private String scopeText = null; private int categoryId = -1; private String location = null; private int filter = BEST_MATCH; // helper properties private String parsedQuery = null; private String parsedLocation = null; private ArrayList<String> terms = null; private ArrayList<String> locationTerms = null; private int numberFound = 0; private boolean valid = false; /** * Constructor for the SearchBean object */ public SearchBean() { } /** * Gets the query attribute of the SearchBean object * * @return The query value */ public String getQuery() { return query; } /** * Sets the query attribute of the SearchBean object * * @param tmp The new query value */ public void setQuery(String tmp) { if (StringUtils.hasText(tmp)) { this.query = tmp; } else { this.query = null; parsedQuery = null; terms = null; } } public String getLocation() { return location; } public void setLocation(String tmp) { if (StringUtils.hasText(tmp)) { this.location = tmp; } else { this.location = null; parsedLocation = null; locationTerms = null; } } /** * Gets the scope attribute of the SearchBean object * * @return The scope value */ public int getScope() { return scope; } /** * Sets the scope attribute of the SearchBean object * * @param tmp The new scope value */ public void setScope(int tmp) { this.scope = tmp; } /** * Gets the section attribute of the SearchBean object * * @return The section value */ public int getSection() { return section; } /** * Sets the section attribute of the SearchBean object * * @param tmp The new section value */ public void setSection(int tmp) { this.section = tmp; } /** * Sets the section attribute of the SearchBean object * * @param tmp The new section value */ public void setSection(String tmp) { this.section = Integer.parseInt(tmp); } /** * Sets the type attribute of the SearchBean object * * @param tmp The new type value */ public void setType(String tmp) { scope = UNDEFINED; type = ""; if (tmp != null && tmp.length() > 0) { if ("this".equals(tmp)) { scope = THIS; } else if ("all".equals(tmp)) { scope = ALL; } } // Validate the input if (scope != UNDEFINED) { type = tmp; } } public String getType() { return type; } /** * Sets the scope attribute of the SearchBean object * * @param tmp The new scope value */ public void setScope(String tmp) { // section section = UNDEFINED; scopeText = ""; if (tmp != null && tmp.length() > 0) { if ("allNews".equals(tmp) || "allBlog".equals(tmp)) { section = NEWS; } else if ("allDiscussion".equals(tmp)) { section = DISCUSSION; } else if ("allDocuments".equals(tmp)) { section = DOCUMENTS; } else if ("allLists".equals(tmp)) { section = LISTS; } else if ("allPlan".equals(tmp)) { section = PLAN; } else if ("allTickets".equals(tmp)) { section = TICKETS; } else if ("allDetails".equals(tmp)) { section = DETAILS; } else if ("allWiki".equals(tmp)) { section = WIKI; } else if ("allWebsite".equals(tmp)) { section = WEBSITE; } else if ("allAds".equals(tmp) || "allPromotions".equals(tmp)) { section = ADS; } else if ("allClassifieds".equals(tmp)) { section = CLASSIFIEDS; } else if ("allReviews".equals(tmp)) { section = REVIEWS; } } // Validate the input if (section != UNDEFINED) { scopeText = tmp; } } /** * Gets the projectId attribute of the SearchBean object * * @return The projectId value */ public int getProjectId() { return projectId; } /** * Sets the projectId attribute of the SearchBean object * * @param tmp The new projectId value */ public void setProjectId(int tmp) { this.projectId = tmp; } /** * Sets the projectId attribute of the SearchBean object * * @param tmp The new projectId value */ public void setProjectId(String tmp) { this.projectId = Integer.parseInt(tmp); } public int getCategoryId() { return categoryId; } public void setCategoryId(int categoryId) { this.categoryId = categoryId; } public void setCategoryId(String tmp) { this.categoryId = Integer.parseInt(tmp); } public boolean getOpenProjectsOnly() { return openProjectsOnly; } public void setOpenProjectsOnly(boolean openProjectOnly) { this.openProjectsOnly = openProjectOnly; } public void setOpenProjectsOnly(String tmp) { this.openProjectsOnly = DatabaseUtils.parseBoolean(tmp); } public String getScopeText() { return scopeText; } public void setScopeText(String scopeText) { this.scopeText = scopeText; } /** * Gets the valid attribute of the SearchBean object * * @return The valid value */ public boolean isValid() { return valid; } /** * Gets the parsedQuery attribute of the SearchBean object * * @return The parsedQuery value */ public String getParsedQuery() { return parsedQuery; } /** * Sets the parsedQuery attribute of the SearchBean object * * @param tmp The new parsedQuery value */ public void setParsedQuery(String tmp) { this.parsedQuery = tmp; } public String getParsedLocation() { return parsedLocation; } public void setParsedLocation(String parsedLocation) { this.parsedLocation = parsedLocation; } /** * Gets the terms attribute of the SearchBean object * * @return The terms value */ public ArrayList<String> getTerms() { return terms; } /** * Sets the terms attribute of the SearchBean object * * @param tmp The new terms value */ public void setTerms(ArrayList<String> tmp) { this.terms = tmp; } public ArrayList getLocationTerms() { return locationTerms; } public void setLocationTerms(ArrayList<String> locationTerms) { this.locationTerms = locationTerms; } public int getFilter() { return filter; } public void setFilter(int filter) { this.filter = filter; } public void setFilter(String filter) { this.filter = Integer.parseInt(filter); } /** * Adds a feature to the NumberFound attribute of the SearchBean object * * @param count The feature to be added to the NumberFound attribute */ public void addNumberFound(int count) { numberFound += count; } /** * Description of the Method * * @return Description of the Return Value */ public boolean parseQuery() { valid = false; // break up the query string into pieces to be used for building database queries if (query == null || "".equals(query.trim())) { return false; } // get rid of lucene query params parsedQuery = parseToAllowedSearch(query); if (parsedQuery == null) { return false; } // The terms are for highlighting and optimizing terms = SearchUtils.parseSearchTerms(parsedQuery); if (terms.size() == 0) { return false; } valid = true; LOG.debug("SearchBean-> Terms: (" + terms.size() + ") " + terms.toString()); if (location != null) { parsedLocation = parseToAllowedSearch(location); if (parsedLocation != null) { locationTerms = SearchUtils.parseSearchTerms(parsedLocation); LOG.debug("SearchBean-> Location: (" + locationTerms.size() + ") " + locationTerms.toString()); } } return true; } public static String parseToAllowedSearch(String query) { boolean validChar = false; StringBuffer sb = new StringBuffer(); for (int i = 0; i < query.length(); i++) { // Lucene requires escaping: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ if ("&".indexOf(query.charAt(i)) > -1) { sb.append(" \\" + query.charAt(i) + " "); } else if ("():[]{}-+?~&|!^\\\"* ".indexOf(query.charAt(i)) == -1) { sb.append(query.charAt(i)); validChar = true; } else { sb.append(" "); } } if (validChar) { if (!StringUtils.includesAny("abcdefghijklmnopqrstuvwxyz0123456789", sb.toString().toLowerCase())) { return null; } return SearchUtils.parseSearchText(sb.toString(), false); } return null; } public Map<String, String[]> getParameterMap() { Map<String, String[]> map = new HashMap<String, String[]>(); map.put("categoryId", new String[]{"" + categoryId}); map.put("query", new String[]{getQuery()}); map.put("location", new String[]{getLocation()}); map.put("scope", new String[]{getScopeText()}); map.put("type", new String[]{getType()}); map.put("filter", new String[]{"" + getFilter()}); map.put("projectId", new String[]{"" + projectId}); map.put("openProjectsOnly", new String[]{"" + openProjectsOnly}); map.put("auto-populate", new String[]{"true"}); return map; } public String getUrlByFilter(int newFilter) { return "/search?categoryId=" + categoryId + "&query=" + StringUtils.encodeUrl(getQuery()) + "&location=" + StringUtils.encodeUrl(getLocation()) + "&scope=" + StringUtils.encodeUrl(getScopeText()) + "&type=" + StringUtils.encodeUrl(getType()) + "&filter=" + newFilter + "&projectId=" + projectId + "&openProjectsOnly=" + openProjectsOnly + "&auto-populate=true"; } public String getUrlByCategory(int newCategoryId) { return "/search?categoryId=" + newCategoryId + "&query=" + StringUtils.encodeUrl(getQuery()) + "&location=" + StringUtils.encodeUrl(getLocation()) + "&scope=" + StringUtils.encodeUrl(getScopeText()) + "&type=" + StringUtils.encodeUrl(getType()) + "&filter=" + getFilter() + "&projectId=" + projectId + "&openProjectsOnly=" + openProjectsOnly + "&auto-populate=true"; } }