001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Thomas Roger 016 * Nelson Silva 017 */ 018 019package org.nuxeo.search.ui; 020 021import static org.nuxeo.search.ui.localconfiguration.Constants.SEARCH_CONFIGURATION_FACET; 022 023import java.io.Serializable; 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.core.api.CoreSession; 032import org.nuxeo.ecm.core.api.DocumentModel; 033import org.nuxeo.ecm.core.api.SortInfo; 034import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 035import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; 036import org.nuxeo.ecm.platform.actions.Action; 037import org.nuxeo.ecm.platform.actions.ActionContext; 038import org.nuxeo.ecm.platform.actions.ejb.ActionManager; 039import org.nuxeo.ecm.platform.contentview.jsf.ContentViewHeader; 040import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; 041import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; 042import org.nuxeo.ecm.platform.contentview.jsf.ContentViewStateImpl; 043import org.nuxeo.ecm.platform.query.api.PageProvider; 044import org.nuxeo.ecm.platform.query.api.PageProviderService; 045import org.nuxeo.ecm.platform.userworkspace.api.UserWorkspaceService; 046import org.nuxeo.runtime.api.Framework; 047import org.nuxeo.search.ui.localconfiguration.SearchConfiguration; 048 049/** 050 * @since 6.0 051 */ 052public class SearchUIServiceImpl implements SearchUIService { 053 054 private static Log log = LogFactory.getLog(SearchUIServiceImpl.class); 055 056 public static final String SEARCH_CONTENT_VIEWS_CATEGORY = "SEARCH_CONTENT_VIEWS"; 057 058 public static final String CONTENT_VIEW_NAME_PROPERTY = "contentViewName"; 059 060 public static final String SAVED_SEARCHES_PROVIDER_NAME = "SAVED_SEARCHES"; 061 062 public static final String SHARED_SEARCHES_PROVIDER_NAME = "SHARED_SAVED_SEARCHES"; 063 064 public static final String CONTENT_VIEW_DISPLAY_FACET = "ContentViewDisplay"; 065 066 @Override 067 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext) { 068 return getContentViewHeaders(actionContext, null); 069 } 070 071 @Override 072 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext, DocumentModel doc) { 073 ActionManager actionService = Framework.getService(ActionManager.class); 074 List<Action> actions = actionService.getActions(SEARCH_CONTENT_VIEWS_CATEGORY, actionContext); 075 076 List<String> contentViewNames = new ArrayList<>(); 077 for (Action action : actions) { 078 String contentViewName = (String) action.getProperties().get(CONTENT_VIEW_NAME_PROPERTY); 079 if (contentViewName != null) { 080 contentViewNames.add(contentViewName); 081 } 082 } 083 contentViewNames = filterContentViewNames(contentViewNames, doc); 084 085 ContentViewService contentViewService = Framework.getLocalService(ContentViewService.class); 086 List<ContentViewHeader> contentViewHeaders = new ArrayList<>(); 087 for (String contentViewName : contentViewNames) { 088 ContentViewHeader contentViewHeader = contentViewService.getContentViewHeader(contentViewName); 089 if (contentViewHeader != null) { 090 contentViewHeaders.add(contentViewHeader); 091 } 092 } 093 return contentViewHeaders; 094 } 095 096 /** 097 * Returns the filtered content view names based on the local configuration if any. 098 */ 099 protected List<String> filterContentViewNames(List<String> contentViewNames, DocumentModel currentDoc) { 100 SearchConfiguration searchConfiguration = getSearchConfiguration(currentDoc); 101 return searchConfiguration == null ? contentViewNames 102 : searchConfiguration.filterAllowedContentViewNames(contentViewNames); 103 } 104 105 protected SearchConfiguration getSearchConfiguration(DocumentModel currentDoc) { 106 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 107 return localConfigurationService.getConfiguration(SearchConfiguration.class, SEARCH_CONFIGURATION_FACET, 108 currentDoc); 109 } 110 111 public DocumentModel saveSearch(CoreSession session, ContentViewState searchContentViewState, String title) { 112 UserWorkspaceService userWorkspaceService = Framework.getLocalService(UserWorkspaceService.class); 113 DocumentModel uws = userWorkspaceService.getCurrentUserPersonalWorkspace(session, null); 114 115 DocumentModel searchDoc = searchContentViewState.getSearchDocumentModel(); 116 searchDoc.setPropertyValue("dc:title", title); 117 118 if (searchDoc.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 119 searchDoc.setPropertyValue("cvd:contentViewName", searchContentViewState.getContentViewName()); 120 List<SortInfo> sortInfos = searchContentViewState.getSortInfos(); 121 if (sortInfos != null) { 122 ArrayList<Map<String, Serializable>> list = new ArrayList<>(); 123 for (SortInfo sortInfo : sortInfos) { 124 list.add(SortInfo.asMap(sortInfo)); 125 } 126 searchDoc.setPropertyValue("cvd:sortInfos", list); 127 } 128 searchDoc.setPropertyValue("cvd:selectedLayoutColumns", (Serializable) searchContentViewState.getResultColumns()); 129 } else { 130 log.warn(String.format("Search document type %s is missing %s facet", searchDoc.getType(), 131 CONTENT_VIEW_DISPLAY_FACET)); 132 } 133 134 PathSegmentService pathService = Framework.getLocalService(PathSegmentService.class); 135 searchDoc.setPathInfo(uws.getPathAsString(), pathService.generatePathSegment(searchDoc)); 136 searchDoc = session.createDocument(searchDoc); 137 session.save(); 138 139 return searchDoc; 140 } 141 142 public List<DocumentModel> getCurrentUserSavedSearches(CoreSession session) { 143 return getDocuments(SAVED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 144 } 145 146 @SuppressWarnings("unchecked") 147 protected List<DocumentModel> getDocuments(String pageProviderName, CoreSession session, Object... parameters) 148 { 149 PageProviderService pageProviderService = Framework.getService(PageProviderService.class); 150 Map<String, Serializable> properties = new HashMap<String, Serializable>(); 151 properties.put("coreSession", (Serializable) session); 152 return ((PageProvider<DocumentModel>) pageProviderService.getPageProvider(pageProviderName, null, null, null, 153 properties, parameters)).getCurrentPage(); 154 155 } 156 157 public List<DocumentModel> getSharedSavedSearches(CoreSession session) { 158 return getDocuments(SHARED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 159 } 160 161 @Override 162 @SuppressWarnings("unchecked") 163 public ContentViewState loadSearch(DocumentModel savedSearch) { 164 if (!savedSearch.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 165 log.warn(String.format("Search document type %s is missing %s facet", savedSearch.getType(), 166 CONTENT_VIEW_DISPLAY_FACET)); 167 return null; 168 } 169 ContentViewState state = new ContentViewStateImpl(); 170 state.setContentViewName((String) savedSearch.getPropertyValue("cvd:contentViewName")); 171 state.setSearchDocumentModel(savedSearch); 172 state.setSortInfos(getSortInfos(savedSearch)); 173 state.setResultColumns((List<String>) savedSearch.getPropertyValue("cvd:selectedLayoutColumns")); 174 return state; 175 } 176 177 @SuppressWarnings("unchecked") 178 List<SortInfo> getSortInfos(DocumentModel savedSearch) { 179 List<Map<String, Serializable>> list = (List<Map<String, Serializable>>) savedSearch.getPropertyValue( 180 "cvd:sortInfos"); 181 List<SortInfo> sortInfos = new ArrayList<>(); 182 for (Map<String, Serializable> info : list) { 183 sortInfos.add(SortInfo.asSortInfo(info)); 184 } 185 return sortInfos; 186 } 187}