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.DocumentModelFactory; 036import org.nuxeo.ecm.core.api.DocumentRef; 037import org.nuxeo.ecm.core.api.SortInfo; 038import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; 039import org.nuxeo.ecm.core.api.pathsegment.PathSegmentService; 040import org.nuxeo.ecm.platform.actions.Action; 041import org.nuxeo.ecm.platform.actions.ActionContext; 042import org.nuxeo.ecm.platform.actions.ejb.ActionManager; 043import org.nuxeo.ecm.platform.contentview.jsf.ContentViewHeader; 044import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; 045import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; 046import org.nuxeo.ecm.platform.contentview.jsf.ContentViewStateImpl; 047import org.nuxeo.ecm.platform.query.api.PageProvider; 048import org.nuxeo.ecm.platform.query.api.PageProviderService; 049import org.nuxeo.ecm.platform.userworkspace.api.UserWorkspaceService; 050import org.nuxeo.runtime.api.Framework; 051import org.nuxeo.search.ui.localconfiguration.SearchConfiguration; 052 053/** 054 * @since 6.0 055 */ 056public class SearchUIServiceImpl implements SearchUIService { 057 058 private static Log log = LogFactory.getLog(SearchUIServiceImpl.class); 059 060 public static final String SEARCH_CONTENT_VIEWS_CATEGORY = "SEARCH_CONTENT_VIEWS"; 061 062 public static final String CONTENT_VIEW_NAME_PROPERTY = "contentViewName"; 063 064 public static final String SAVED_SEARCHES_PROVIDER_NAME = "SAVED_SEARCHES"; 065 066 public static final String SHARED_SEARCHES_PROVIDER_NAME = "SHARED_SAVED_SEARCHES"; 067 068 public static final String CONTENT_VIEW_DISPLAY_FACET = "ContentViewDisplay"; 069 070 @Override 071 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext) { 072 return getContentViewHeaders(actionContext, null); 073 } 074 075 @Override 076 public List<ContentViewHeader> getContentViewHeaders(ActionContext actionContext, DocumentModel doc) { 077 ActionManager actionService = Framework.getService(ActionManager.class); 078 List<Action> actions = actionService.getActions(SEARCH_CONTENT_VIEWS_CATEGORY, actionContext); 079 080 List<String> contentViewNames = new ArrayList<>(); 081 for (Action action : actions) { 082 String contentViewName = (String) action.getProperties().get(CONTENT_VIEW_NAME_PROPERTY); 083 if (contentViewName != null) { 084 contentViewNames.add(contentViewName); 085 } 086 } 087 contentViewNames = filterContentViewNames(contentViewNames, doc); 088 089 ContentViewService contentViewService = Framework.getService(ContentViewService.class); 090 List<ContentViewHeader> contentViewHeaders = new ArrayList<>(); 091 for (String contentViewName : contentViewNames) { 092 ContentViewHeader contentViewHeader = contentViewService.getContentViewHeader(contentViewName); 093 if (contentViewHeader != null) { 094 contentViewHeaders.add(contentViewHeader); 095 } 096 } 097 return contentViewHeaders; 098 } 099 100 /** 101 * Returns the filtered content view names based on the local configuration if any. 102 */ 103 protected List<String> filterContentViewNames(List<String> contentViewNames, DocumentModel currentDoc) { 104 SearchConfiguration searchConfiguration = getSearchConfiguration(currentDoc); 105 return searchConfiguration == null ? contentViewNames 106 : searchConfiguration.filterAllowedContentViewNames(contentViewNames); 107 } 108 109 protected SearchConfiguration getSearchConfiguration(DocumentModel currentDoc) { 110 LocalConfigurationService localConfigurationService = Framework.getService(LocalConfigurationService.class); 111 return localConfigurationService.getConfiguration(SearchConfiguration.class, SEARCH_CONFIGURATION_FACET, 112 currentDoc); 113 } 114 115 public DocumentModel saveSearch(CoreSession session, ContentViewState searchContentViewState, String title) { 116 UserWorkspaceService userWorkspaceService = Framework.getService(UserWorkspaceService.class); 117 DocumentModel uws = userWorkspaceService.getCurrentUserPersonalWorkspace(session, null); 118 119 DocumentModel searchDoc = searchContentViewState.getSearchDocumentModel(); 120 DocumentRef ref = searchDoc.getRef(); 121 if (ref != null && session.exists(ref)) { 122 // already a saved search, init a new doc 123 DocumentModel bareDoc = DocumentModelFactory.createDocumentModel(searchDoc.getType()); 124 bareDoc.copyContent(searchDoc); 125 searchDoc = bareDoc; 126 } 127 searchDoc.setPropertyValue("dc:title", title); 128 129 if (searchDoc.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 130 searchDoc.setPropertyValue("cvd:contentViewName", searchContentViewState.getContentViewName()); 131 searchDoc.setPropertyValue("saved:providerName", searchContentViewState.getPageProviderName()); 132 searchDoc.setPropertyValue("saved:pageSize", searchContentViewState.getPageSize()); 133 searchContentViewState.getPageSize(); 134 List<SortInfo> sortInfos = searchContentViewState.getSortInfos(); 135 if (sortInfos != null) { 136 ArrayList<Map<String, Serializable>> list = new ArrayList<>(); 137 String sortBy = "", sortOrder = ""; 138 for (SortInfo sortInfo : sortInfos) { 139 if (!sortBy.isEmpty()) { 140 sortBy += ","; 141 sortOrder += ","; 142 } 143 sortBy += sortInfo.getSortColumn(); 144 sortOrder += sortInfo.getSortAscending() ? "ASC" : "DESC"; 145 list.add(SortInfo.asMap(sortInfo)); 146 } 147 searchDoc.setPropertyValue("cvd:sortInfos", list); 148 searchDoc.setPropertyValue("saved:sortBy", sortBy); 149 searchDoc.setPropertyValue("saved:sortOrder", sortOrder); 150 } 151 searchDoc.setPropertyValue("cvd:selectedLayoutColumns", 152 (Serializable) searchContentViewState.getResultColumns()); 153 } else { 154 log.warn(String.format("Search document type %s is missing %s facet", searchDoc.getType(), 155 CONTENT_VIEW_DISPLAY_FACET)); 156 } 157 158 PathSegmentService pathService = Framework.getService(PathSegmentService.class); 159 searchDoc.setPathInfo(uws.getPathAsString(), pathService.generatePathSegment(searchDoc)); 160 searchDoc = session.createDocument(searchDoc); 161 session.save(); 162 163 return searchDoc; 164 } 165 166 public List<DocumentModel> getCurrentUserSavedSearches(CoreSession session) { 167 return getDocuments(SAVED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 168 } 169 170 @SuppressWarnings("unchecked") 171 protected List<DocumentModel> getDocuments(String pageProviderName, CoreSession session, Object... parameters) { 172 PageProviderService pageProviderService = Framework.getService(PageProviderService.class); 173 Map<String, Serializable> properties = new HashMap<String, Serializable>(); 174 properties.put("coreSession", (Serializable) session); 175 return ((PageProvider<DocumentModel>) pageProviderService.getPageProvider(pageProviderName, null, null, null, 176 properties, parameters)).getCurrentPage(); 177 178 } 179 180 public List<DocumentModel> getSharedSavedSearches(CoreSession session) { 181 return getDocuments(SHARED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 182 } 183 184 @Override 185 @SuppressWarnings("unchecked") 186 public ContentViewState loadSearch(DocumentModel savedSearch) { 187 if (!savedSearch.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 188 log.warn(String.format("Search document type %s is missing %s facet", savedSearch.getType(), 189 CONTENT_VIEW_DISPLAY_FACET)); 190 return null; 191 } 192 ContentViewState state = new ContentViewStateImpl(); 193 state.setContentViewName((String) savedSearch.getPropertyValue("cvd:contentViewName")); 194 state.setSearchDocumentModel(savedSearch); 195 state.setSortInfos(getSortInfos(savedSearch)); 196 state.setResultColumns((List<String>) savedSearch.getPropertyValue("cvd:selectedLayoutColumns")); 197 return state; 198 } 199 200 @SuppressWarnings("unchecked") 201 List<SortInfo> getSortInfos(DocumentModel savedSearch) { 202 List<Map<String, Serializable>> list = (List<Map<String, Serializable>>) savedSearch.getPropertyValue( 203 "cvd:sortInfos"); 204 List<SortInfo> sortInfos = new ArrayList<>(); 205 for (Map<String, Serializable> info : list) { 206 sortInfos.add(SortInfo.asSortInfo(info)); 207 } 208 return sortInfos; 209 } 210}