001/* 002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Thomas Roger 018 * Nelson Silva 019 */ 020 021package org.nuxeo.search.ui; 022 023import static org.nuxeo.search.ui.localconfiguration.Constants.SEARCH_CONFIGURATION_FACET; 024 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.nuxeo.ecm.core.api.CoreSession; 034import org.nuxeo.ecm.core.api.DocumentModel; 035import org.nuxeo.ecm.core.api.SortInfo; 036import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 037import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; 038import org.nuxeo.ecm.platform.actions.Action; 039import org.nuxeo.ecm.platform.actions.ActionContext; 040import org.nuxeo.ecm.platform.actions.ejb.ActionManager; 041import org.nuxeo.ecm.platform.contentview.jsf.ContentViewHeader; 042import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; 043import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; 044import org.nuxeo.ecm.platform.contentview.jsf.ContentViewStateImpl; 045import org.nuxeo.ecm.platform.query.api.PageProvider; 046import org.nuxeo.ecm.platform.query.api.PageProviderService; 047import org.nuxeo.ecm.platform.userworkspace.api.UserWorkspaceService; 048import org.nuxeo.runtime.api.Framework; 049import org.nuxeo.search.ui.localconfiguration.SearchConfiguration; 050 051/** 052 * @since 6.0 053 */ 054public class SearchUIServiceImpl implements SearchUIService { 055 056 private static Log log = LogFactory.getLog(SearchUIServiceImpl.class); 057 058 public static final String SEARCH_CONTENT_VIEWS_CATEGORY = "SEARCH_CONTENT_VIEWS"; 059 060 public static final String CONTENT_VIEW_NAME_PROPERTY = "contentViewName"; 061 062 public static final String SAVED_SEARCHES_PROVIDER_NAME = "SAVED_SEARCHES"; 063 064 public static final String SHARED_SEARCHES_PROVIDER_NAME = "SHARED_SAVED_SEARCHES"; 065 066 public static final String CONTENT_VIEW_DISPLAY_FACET = "ContentViewDisplay"; 067 068 @Override 069 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext) { 070 return getContentViewHeaders(actionContext, null); 071 } 072 073 @Override 074 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext, DocumentModel doc) { 075 ActionManager actionService = Framework.getService(ActionManager.class); 076 List<Action> actions = actionService.getActions(SEARCH_CONTENT_VIEWS_CATEGORY, actionContext); 077 078 List<String> contentViewNames = new ArrayList<>(); 079 for (Action action : actions) { 080 String contentViewName = (String) action.getProperties().get(CONTENT_VIEW_NAME_PROPERTY); 081 if (contentViewName != null) { 082 contentViewNames.add(contentViewName); 083 } 084 } 085 contentViewNames = filterContentViewNames(contentViewNames, doc); 086 087 ContentViewService contentViewService = Framework.getService(ContentViewService.class); 088 List<ContentViewHeader> contentViewHeaders = new ArrayList<>(); 089 for (String contentViewName : contentViewNames) { 090 ContentViewHeader contentViewHeader = contentViewService.getContentViewHeader(contentViewName); 091 if (contentViewHeader != null) { 092 contentViewHeaders.add(contentViewHeader); 093 } 094 } 095 return contentViewHeaders; 096 } 097 098 /** 099 * Returns the filtered content view names based on the local configuration if any. 100 */ 101 protected List<String> filterContentViewNames(List<String> contentViewNames, DocumentModel currentDoc) { 102 SearchConfiguration searchConfiguration = getSearchConfiguration(currentDoc); 103 return searchConfiguration == null ? contentViewNames 104 : searchConfiguration.filterAllowedContentViewNames(contentViewNames); 105 } 106 107 protected SearchConfiguration getSearchConfiguration(DocumentModel currentDoc) { 108 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 109 return localConfigurationService.getConfiguration(SearchConfiguration.class, SEARCH_CONFIGURATION_FACET, 110 currentDoc); 111 } 112 113 public DocumentModel saveSearch(CoreSession session, ContentViewState searchContentViewState, String title) { 114 UserWorkspaceService userWorkspaceService = Framework.getService(UserWorkspaceService.class); 115 DocumentModel uws = userWorkspaceService.getCurrentUserPersonalWorkspace(session, null); 116 117 DocumentModel searchDoc = searchContentViewState.getSearchDocumentModel(); 118 searchDoc.setPropertyValue("dc:title", title); 119 120 if (searchDoc.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 121 searchDoc.setPropertyValue("cvd:contentViewName", searchContentViewState.getContentViewName()); 122 searchDoc.setPropertyValue("saved:providerName", searchContentViewState.getPageProviderName()); 123 searchDoc.setPropertyValue("saved:pageSize", searchContentViewState.getPageSize()); 124 searchContentViewState.getPageSize(); 125 List<SortInfo> sortInfos = searchContentViewState.getSortInfos(); 126 if (sortInfos != null) { 127 ArrayList<Map<String, Serializable>> list = new ArrayList<>(); 128 String sortBy = "", sortOrder = ""; 129 for (SortInfo sortInfo : sortInfos) { 130 if (!sortBy.isEmpty()) { 131 sortBy += ","; 132 sortOrder += ","; 133 } 134 sortBy += sortInfo.getSortColumn(); 135 sortOrder += sortInfo.getSortAscending() ? "ASC" : "DESC"; 136 list.add(SortInfo.asMap(sortInfo)); 137 } 138 searchDoc.setPropertyValue("cvd:sortInfos", list); 139 searchDoc.setPropertyValue("saved:sortBy", sortBy); 140 searchDoc.setPropertyValue("saved:sortOrder", sortOrder); 141 } 142 searchDoc.setPropertyValue("cvd:selectedLayoutColumns", (Serializable) searchContentViewState.getResultColumns()); 143 } else { 144 log.warn(String.format("Search document type %s is missing %s facet", searchDoc.getType(), 145 CONTENT_VIEW_DISPLAY_FACET)); 146 } 147 148 PathSegmentService pathService = Framework.getService(PathSegmentService.class); 149 searchDoc.setPathInfo(uws.getPathAsString(), pathService.generatePathSegment(searchDoc)); 150 searchDoc = session.createDocument(searchDoc); 151 session.save(); 152 153 return searchDoc; 154 } 155 156 public List<DocumentModel> getCurrentUserSavedSearches(CoreSession session) { 157 return getDocuments(SAVED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 158 } 159 160 @SuppressWarnings("unchecked") 161 protected List<DocumentModel> getDocuments(String pageProviderName, CoreSession session, Object... parameters) 162 { 163 PageProviderService pageProviderService = Framework.getService(PageProviderService.class); 164 Map<String, Serializable> properties = new HashMap<String, Serializable>(); 165 properties.put("coreSession", (Serializable) session); 166 return ((PageProvider<DocumentModel>) pageProviderService.getPageProvider(pageProviderName, null, null, null, 167 properties, parameters)).getCurrentPage(); 168 169 } 170 171 public List<DocumentModel> getSharedSavedSearches(CoreSession session) { 172 return getDocuments(SHARED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 173 } 174 175 @Override 176 @SuppressWarnings("unchecked") 177 public ContentViewState loadSearch(DocumentModel savedSearch) { 178 if (!savedSearch.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 179 log.warn(String.format("Search document type %s is missing %s facet", savedSearch.getType(), 180 CONTENT_VIEW_DISPLAY_FACET)); 181 return null; 182 } 183 ContentViewState state = new ContentViewStateImpl(); 184 state.setContentViewName((String) savedSearch.getPropertyValue("cvd:contentViewName")); 185 state.setSearchDocumentModel(savedSearch); 186 state.setSortInfos(getSortInfos(savedSearch)); 187 state.setResultColumns((List<String>) savedSearch.getPropertyValue("cvd:selectedLayoutColumns")); 188 return state; 189 } 190 191 @SuppressWarnings("unchecked") 192 List<SortInfo> getSortInfos(DocumentModel savedSearch) { 193 List<Map<String, Serializable>> list = (List<Map<String, Serializable>>) savedSearch.getPropertyValue( 194 "cvd:sortInfos"); 195 List<SortInfo> sortInfos = new ArrayList<>(); 196 for (Map<String, Serializable> info : list) { 197 sortInfos.add(SortInfo.asSortInfo(info)); 198 } 199 return sortInfos; 200 } 201}