/*
* Copyright (C) 2003-2008 eXo Platform SAS.
*
* 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 General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.wcm.webui.search;
import java.text.DateFormat;
import java.text.Normalizer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import org.exoplatform.commons.utils.ISO8601;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.commons.utils.ObjectPageList;
import org.exoplatform.commons.utils.PageList;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.portal.mop.SiteType;
import org.exoplatform.portal.webui.container.UIContainer;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.resolver.ResourceResolver;
import org.exoplatform.services.cms.templates.TemplateService;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.portal.LivePortalManagerService;
import org.exoplatform.services.wcm.publication.WCMComposer;
import org.exoplatform.services.wcm.search.QueryCriteria;
import org.exoplatform.services.wcm.search.ResultNode;
import org.exoplatform.services.wcm.search.SiteSearchService;
import org.exoplatform.services.wcm.search.base.AbstractPageList;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
import org.exoplatform.wcm.webui.Utils;
import org.exoplatform.wcm.webui.paginator.UICustomizeablePaginator;
import org.exoplatform.web.application.ApplicationMessage;
import org.exoplatform.web.url.navigation.NavigationResource;
import org.exoplatform.web.url.navigation.NodeURL;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.application.portlet.PortletRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.ComponentConfigs;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIApplication;
import org.exoplatform.webui.core.lifecycle.Lifecycle;
import org.exoplatform.webui.form.UIFormHiddenInput;
import org.exoplatform.webui.form.UIFormRadioBoxInput;
/*
* Created by The eXo Platform SAS Author : Anh Do Ngoc anh.do@exoplatform.com
* Oct 31, 2008
*/
@SuppressWarnings("deprecation")
@ComponentConfigs( {
@ComponentConfig(lifecycle = Lifecycle.class),
@ComponentConfig(type = UICustomizeablePaginator.class,
events = @EventConfig(listeners = UICustomizeablePaginator.ShowPageActionListener.class)) })
public class UISearchResult extends UIContainer {
/** The template path. */
private String templatePath;
/** The resource resolver. */
private ResourceResolver resourceResolver;
/** The ui paginator. */
private UICustomizeablePaginator uiPaginator;
/** The keyword. */
private String keyword;
/** The result type. */
private String resultType;
/** The suggestion. */
private String suggestion;
/** The suggestion. */
private String suggestionURL;
/** The PageMode */
private String pageMode;
/** The date formatter. */
private SimpleDateFormat dateFormatter = new SimpleDateFormat(ISO8601.SIMPLE_DATETIME_FORMAT);
/** The search time. */
private float searchTime;
/** The search result in "More" mode */
private List<ResultNode> moreListResult;
/** The page that already queried (used only in "More" mode */
private Set<Integer> morePageSet;
/** The Constant PARAMETER_REGX. */
public final static String PARAMETER_REGX = "(portal=.*)&(keyword=.*)";
/** The Constant RESULT_NOT_FOUND. */
public final static String RESULT_NOT_FOUND = "UISearchResult.msg.result-not-found";
/**
* Inits the.
*
* @param templatePath the template path
* @param resourceResolver the resource resolver
* @throws Exception the exception
*/
public void init(String templatePath, ResourceResolver resourceResolver) throws Exception {
PortletRequestContext portletRequestContext = (PortletRequestContext) WebuiRequestContext.getCurrentInstance();
PortletPreferences portletPreferences = portletRequestContext.getRequest().getPreferences();
String paginatorTemplatePath = portletPreferences.getValue(UIWCMSearchPortlet.SEARCH_PAGINATOR_TEMPLATE_PATH,
null);
this.pageMode = portletPreferences.getValue(UIWCMSearchPortlet.PAGE_MODE, SiteSearchService.PAGE_MODE_NONE);
this.templatePath = templatePath;
this.resourceResolver = resourceResolver;
uiPaginator = addChild(UICustomizeablePaginator.class, null, null);
uiPaginator.setTemplatePath(paginatorTemplatePath);
uiPaginator.setResourceResolver(resourceResolver);
uiPaginator.setPageMode(pageMode);
clearResult();
}
/*
* (non-Javadoc)
* @see
* org.exoplatform.webui.core.UIComponent#processRender(org.exoplatform.webui
* .application.WebuiRequestContext)
*/
public void processRender(WebuiRequestContext context) throws Exception {
PortletRequestContext porletRequestContext = (PortletRequestContext) context;
PortletPreferences portletPreferences = porletRequestContext.getRequest().getPreferences();
if (resultType == null || resultType.trim().length() == 0) {
resultType = "Document";
}
PortalRequestContext portalRequestContext = Util.getPortalRequestContext();
String portal = portalRequestContext.getRequestParameter("portal");
String keyword = portalRequestContext.getRequestParameter("keyword");
if ((portal != null) && (keyword != null) && (keyword.length() > 0)) {
UISearchPageLayout uiSearchPageContainer = getAncestorOfType(UISearchPageLayout.class);
UISearchForm searchForm = uiSearchPageContainer.getChild(UISearchForm.class);
// searchForm.getUIFormSelectBox(UISearchForm.PORTALS_SELECTOR).setSelectedValues(new
// String[] {portal});
searchForm.getUIStringInput(UISearchForm.KEYWORD_INPUT).setValue(keyword);
if (searchForm.getUIFormSelectBox(UISearchForm.PORTALS_SELECTOR).getValue() != null) {
portal = searchForm.getUIFormSelectBox(UISearchForm.PORTALS_SELECTOR).getValue();
}
if (searchForm.getUIStringInput(UISearchForm.KEYWORD_INPUT).getValue() != null) {
keyword = searchForm.getUIStringInput(UISearchForm.KEYWORD_INPUT).getValue();
}
setKeyword(keyword);
keyword = Normalizer.normalize(keyword, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
SiteSearchService siteSearchService = getApplicationComponent(SiteSearchService.class);
QueryCriteria queryCriteria = new QueryCriteria();
UIFormRadioBoxInput searchOption = searchForm.getUIFormRadioBoxInput(UISearchForm.SEARCH_OPTION);
boolean isSearchDocument = (searchOption.getValue().equals(UISearchForm.DOCUMENT_CHECKING));
boolean isWebPage = (searchOption.getValue().equals(UISearchForm.PAGE_CHECKING));
List<String> documentNodeTypes = new ArrayList<String>();
if (isSearchDocument) {
TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
documentNodeTypes = templateService.getAllDocumentNodeTypes();
portal = Util.getPortalRequestContext().getPortalOwner();
resultType = "Document";
} else {
documentNodeTypes.add("gtn:language");
documentNodeTypes.add("exo:pageMetadata");
queryCriteria.setFulltextSearchProperty(new String[] {"exo:metaKeywords", "exo:metaDescription", "gtn:name"});
resultType = "Page";
}
String pageMode = portletPreferences.getValue(UIWCMSearchPortlet.PAGE_MODE, SiteSearchService.PAGE_MODE_NONE);
queryCriteria.setContentTypes(documentNodeTypes.toArray(new String[documentNodeTypes.size()]));
queryCriteria.setSiteName(portal);
queryCriteria.setKeyword(
org.exoplatform.services.cms.impl.Utils.escapeIllegalCharacterInQuery(keyword).toLowerCase());
queryCriteria.setSearchWebpage(isWebPage);
queryCriteria.setSearchDocument(isSearchDocument);
queryCriteria.setSearchWebContent(isSearchDocument);
queryCriteria.setPageMode(pageMode);
queryCriteria.setLiveMode(WCMComposer.MODE_LIVE.equals(Utils.getCurrentMode()));
queryCriteria.setSortBy(this.getSortField());
queryCriteria.setOrderBy(this.getOrderType());
int itemsPerPage = Integer.parseInt(portletPreferences.getValue(UIWCMSearchPortlet.ITEMS_PER_PAGE,
null));
try {
AbstractPageList<ResultNode> pageList = null;
if (isWebPage) {
pageList = siteSearchService.searchPageContents(WCMCoreUtils.getSystemSessionProvider(),
queryCriteria,
itemsPerPage,
false);
} else {
pageList = siteSearchService.searchSiteContents(WCMCoreUtils.getUserSessionProvider(),
queryCriteria,
itemsPerPage,
false);
}
setSearchTime(pageList.getQueryTime() / 1000);
setSuggestion(pageList.getSpellSuggestion());
if (pageList.getAvailable() <= 0) {
String suggestion = pageList.getSpellSuggestion();
setSuggestionURL(suggestion);
searchForm.setSubmitAction(suggestion);
}
setPageList(pageList);
} catch (Exception e) {
UIApplication uiApp = getAncestorOfType(UIApplication.class);
uiApp.addMessage(new ApplicationMessage(UISearchForm.MESSAGE_NOT_SUPPORT_KEYWORD,
null,
ApplicationMessage.WARNING));
}
}
super.processRender(context);
}
/**
* Sets the page list.
*
* @param dataPageList the new page list
*/
@SuppressWarnings("unchecked")
public void setPageList(PageList dataPageList) {
uiPaginator.setPageList(dataPageList);
moreListResult = new ArrayList<ResultNode>();
morePageSet = new HashSet<Integer>();
}
/**
* Gets the total item.
*
* @return the total item
*/
public int getTotalItem() {
return uiPaginator.getPageList().getAvailable();
}
/**
* Gets the items per page.
*
* @return the items per page
*/
public int getItemsPerPage() {
return uiPaginator.getPageList().getPageSize();
}
/**
* Gets the current page.
*
* @return the current page
*/
public int getCurrentPage() {
return uiPaginator.getCurrentPage();
}
/**
* Gets the page mode
* @return the page mode
*/
public String getPageMode() {
return pageMode;
}
/*
* (non-Javadoc)
* @see org.exoplatform.portal.webui.portal.UIPortalComponent#getTemplate()
*/
public String getTemplate() {
return templatePath;
}
/*
* (non-Javadoc)
* @see
* org.exoplatform.webui.core.UIComponent#getTemplateResourceResolver(org.
* exoplatform.webui.application.WebuiRequestContext, java.lang.String)
*/
public ResourceResolver getTemplateResourceResolver(WebuiRequestContext context, String template) {
return resourceResolver;
}
/**
* Gets the current page data.
*
* @return the current page data
* @throws Exception the exception
*/
@SuppressWarnings("unchecked")
public List getCurrentPageData() throws Exception {
return uiPaginator.getCurrentPageData();
}
/**
* Gets the title.
*
* @param node the node
* @return the title
* @throws Exception the exception
*/
public String getTitle(Node node) throws Exception {
if (UIWCMSearchPortlet.SEARCH_CONTENT_MODE.equals(this.getResultType())) {
return org.exoplatform.ecm.webui.utils.Utils.getTitle(node);
} else {
Session session = node.getSession();
Node mopLink = (Node) session.getItem(node.getPath() + "/mop:link");
if (mopLink != null && mopLink.hasProperty("mop:page")) {
String mopPageLink = mopLink.getProperty("mop:page").getValue().getString();
Node mopPage = (Node) session.getItem(mopPageLink);
if (mopPage != null && mopPage.hasProperty("gtn:name")) {
return mopPage.getProperty("gtn:name").getValue().getString();
} else {
return node.getName().replaceFirst("mop:", "");
}
} else {
return node.getName().replaceFirst("mop:", "");
}
}
}
/**
* Gets the uRL.
*
* @param node the node
* @return the uRL
* @throws Exception the exception
*/
public List<String> getURLs(Node node) throws Exception {
List<String> urls = new ArrayList<String>();
if (!node.hasProperty("publication:navigationNodeURIs")) {
urls.add(getURL(node));
} else {
for (Value value : node.getProperty("publication:navigationNodeURIs").getValues()) {
urls.add(value.getString());
}
}
return urls;
}
/**
* Gets the published node uri.
*
* @param navNodeURI the nav node uri
* @return the published node uri
*/
public String getPublishedNodeURI(String navNodeURI) {
PortalRequestContext portalRequestContext = Util.getPortalRequestContext();
PortletRequest portletRequest = getPortletRequest();
StringBuffer baseURI = new StringBuffer();
baseURI.append(portletRequest.getScheme()).append("://").append(portletRequest.getServerName());
if (portletRequest.getServerPort() != 80) {
baseURI.append(":").append(String.format("%s", portletRequest.getServerPort()));
}
if (navNodeURI.startsWith(baseURI.toString()))
return navNodeURI;
NodeURL nodeURL = portalRequestContext.createURL(NodeURL.TYPE);
NavigationResource resource = new NavigationResource(portalRequestContext.getSiteType(),
portalRequestContext.getSiteName(),
navNodeURI);
nodeURL.setResource(resource);
return baseURI + nodeURL.toString();
}
/**
* Gets the uRL.
*
* @param node the node
* @return the uRL
* @throws Exception the exception
*/
public String getURL(Node node) throws Exception {
PortletRequest portletRequest = getPortletRequest();
PortletPreferences portletPreferences = portletRequest.getPreferences();
String repository = WCMCoreUtils.getRepository().getConfiguration().getName();
String workspace = portletPreferences.getValue(UIWCMSearchPortlet.WORKSPACE, null);
String basePath = portletPreferences.getValue(UIWCMSearchPortlet.BASE_PATH, null);
String detailParameterName = portletPreferences.getValue(UIWCMSearchPortlet.DETAIL_PARAMETER_NAME, null);
StringBuffer path = new StringBuffer();
path.append("/").append(repository).append("/").append(workspace);
NodeURL nodeURL = Util.getPortalRequestContext().createURL(NodeURL.TYPE);
NavigationResource resource = new NavigationResource(SiteType.PORTAL,
Util.getPortalRequestContext()
.getPortalOwner(), basePath);
nodeURL.setResource(resource);
if (node.isNodeType("nt:frozenNode")) {
String uuid = node.getProperty("jcr:frozenUuid").getString();
Node originalNode = node.getSession().getNodeByUUID(uuid);
path.append(originalNode.getPath());
nodeURL.setQueryParameterValue("version", node.getParent().getName());
} else {
path.append(node.getPath());
}
nodeURL.setQueryParameterValue(detailParameterName, path.toString());
nodeURL.setSchemeUse(true);
return nodeURL.toString();
}
private PortletRequest getPortletRequest() {
PortletRequestContext portletRequestContext = WebuiRequestContext.getCurrentInstance();
return portletRequestContext.getRequest();
}
/**
* Gets the created date.
*
* @param node the node
* @return the created date
* @throws Exception the exception
*/
public String getCreatedDate(Node node) throws Exception {
if (node.hasProperty("exo:dateCreated")) {
Calendar calendar = node.getProperty("exo:dateCreated").getValue().getDate();
return dateFormatter.format(calendar.getTime());
}
return null;
}
/**
* Gets the mofified date of search result node.
*
* @param node the node
* @return the mofified date
* @throws Exception the exception
*/
private String getModifiedDate(Node node) throws Exception {
Calendar calendar = node.hasProperty(NodetypeConstant.EXO_LAST_MODIFIED_DATE) ?
node.getProperty(NodetypeConstant.EXO_LAST_MODIFIED_DATE).getDate() :
node.getProperty(NodetypeConstant.EXO_DATE_CREATED).getDate();
DateFormat simpleDateFormat = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.FULL, SimpleDateFormat.SHORT);
return simpleDateFormat.format(calendar.getTime());
}
/**
* Checks if is show paginator.
*
* @return true, if is show paginator
* @throws Exception the exception
*/
public boolean isShowPaginator() throws Exception {
PortletPreferences portletPreferences = ((PortletRequestContext) WebuiRequestContext.getCurrentInstance()).getRequest()
.getPreferences();
String itemsPerPage = portletPreferences.getValue(UIWCMSearchPortlet.ITEMS_PER_PAGE, null);
int totalItems = uiPaginator.getTotalItems();
if (totalItems > Integer.parseInt(itemsPerPage)) {
return true;
}
return false;
}
/**
* Gets the search time.
*
* @return the search time
*/
public float getSearchTime() {
return searchTime;
}
/**
* Sets the search time.
*
* @param searchTime the new search time
*/
public void setSearchTime(float searchTime) {
this.searchTime = searchTime;
}
/**
* Gets the suggestion.
*
* @return the suggestion
*/
public String getSuggestion() {
return suggestion;
}
/**
* Sets the suggestion.
*
* @param suggestion the suggestion
*/
public void setSuggestion(String suggestion) {
this.suggestion = suggestion;
}
/**
* Gets the suggestion URL.
*
* @return the suggestion URL
*/
public String getSuggestionURL() {
return suggestionURL;
}
/**
* Sets the suggestion URL.
*
* @param suggestionURL the suggestion url
*/
public void setSuggestionURL(String suggestionURL) {
this.suggestionURL = suggestionURL;
}
/**
* Gets the keyword.
*
* @return the keyword
*/
public String getKeyword() {
return this.keyword;
}
/**
* Sets the keyword.
*
* @param keyword the new keyword
*/
public void setKeyword(String keyword) {
this.keyword = keyword;
}
/**
* Gets the result type.
*
* @return the result type
*/
public String getResultType() {
return this.resultType;
}
/**
* Sets the result type.
*
* @param resultType the new result type
*/
public void setResultType(String resultType) {
this.resultType = resultType;
}
/**
* Gets the number of page.
*
* @return the number of page
*/
public int getNumberOfPage() {
return uiPaginator.getPageList().getAvailablePage();
}
/**
* Clears the displayed result list
*/
@SuppressWarnings("unchecked")
public void clearResult() {
moreListResult = new ArrayList<ResultNode>();
morePageSet = new HashSet<Integer>();
PortletPreferences portletPreferences = ((PortletRequestContext) WebuiRequestContext.getCurrentInstance()).getRequest()
.getPreferences();
String itemsPerPage = portletPreferences.getValue(UIWCMSearchPortlet.ITEMS_PER_PAGE, null);
setPageList(new ObjectPageList(new ArrayList<ResultNode>(), Integer.parseInt(itemsPerPage)));
}
/**
* Gets the real node list to display
*
* @return the real node list
*/
public List<ResultNode> getRealCurrentPageData() throws Exception {
int currentPage = getCurrentPage();
if (SiteSearchService.PAGE_MODE_MORE.equals(pageMode)) {
if (!morePageSet.contains(currentPage)) {
morePageSet.add(currentPage);
moreListResult.addAll(getCurrentPageData());
}
}
return SiteSearchService.PAGE_MODE_MORE.equals(pageMode) ? moreListResult : getCurrentPageData();
}
/**
* Get string used to describe search result node.
*
* @param resultNode ResultNode
* @return result node description
* @throws Exception
*/
private String getDetail(ResultNode resultNode) throws Exception {
Node realNode = org.exoplatform.wcm.webui.Utils.getRealNode(resultNode.getNode());
String resultType = this.getResultType();
if (UIWCMSearchPortlet.SEARCH_CONTENT_MODE.equals(resultType)) {
return WCMCoreUtils.getService(LivePortalManagerService.class).getLivePortalByChild(realNode).getName()
.concat(org.exoplatform.services.cms.impl.Utils.fileSize(realNode))
.concat(" - ")
.concat(getModifiedDate(realNode));
} else {
return StringUtils.substringBefore(StringUtils.substringAfter(realNode.getPath(),
SiteSearchService.PATH_PORTAL_SITES.concat("/mop:")),"/")
.concat(" - ")
.concat(resultNode.getUserNavigationURI());
}
}
/**
* Get resource bundle from given key.
*
* @param key Key
* @return
*/
private String getLabel(String key) {
try {
ResourceBundle rs = WebuiRequestContext.getCurrentInstance().getApplicationResourceBundle();
return rs.getString(key);
} catch (MissingResourceException e) {
return key;
}
}
/**
* Get Order Type ("asc" or "desc") from user criteria.
*
* @return order type
* @throws Exception
*/
private String getOrderType() throws Exception {
UISearchForm uiSearchForm = this.getParent().findFirstComponentOfType(UISearchForm.class);
String orderType = ((UIFormHiddenInput)uiSearchForm.getUIInput(UISearchForm.ORDER_TYPE_HIDDEN_INPUT)).getValue();
return StringUtils.isEmpty(orderType) ? "asc" : orderType;
}
/**
* Get Sort Field from user criteria.
*
* @return sort field used to sort result
*/
private String getSortField() {
UISearchForm uiSearchForm = this.getParent().findFirstComponentOfType(UISearchForm.class);
String sortField = ((UIFormHiddenInput)uiSearchForm.getUIInput(UISearchForm.SORT_FIELD_HIDDEN_INPUT)).getValue();
return StringUtils.isEmpty(sortField) ? "relevancy" : sortField;
}
}