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.getLocalService(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.getLocalService(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 List<SortInfo> sortInfos = searchContentViewState.getSortInfos(); 123 if (sortInfos != null) { 124 ArrayList<Map<String, Serializable>> list = new ArrayList<>(); 125 for (SortInfo sortInfo : sortInfos) { 126 list.add(SortInfo.asMap(sortInfo)); 127 } 128 searchDoc.setPropertyValue("cvd:sortInfos", list); 129 } 130 searchDoc.setPropertyValue("cvd:selectedLayoutColumns", (Serializable) searchContentViewState.getResultColumns()); 131 } else { 132 log.warn(String.format("Search document type %s is missing %s facet", searchDoc.getType(), 133 CONTENT_VIEW_DISPLAY_FACET)); 134 } 135 136 PathSegmentService pathService = Framework.getLocalService(PathSegmentService.class); 137 searchDoc.setPathInfo(uws.getPathAsString(), pathService.generatePathSegment(searchDoc)); 138 searchDoc = session.createDocument(searchDoc); 139 session.save(); 140 141 return searchDoc; 142 } 143 144 public List<DocumentModel> getCurrentUserSavedSearches(CoreSession session) { 145 return getDocuments(SAVED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 146 } 147 148 @SuppressWarnings("unchecked") 149 protected List<DocumentModel> getDocuments(String pageProviderName, CoreSession session, Object... parameters) 150 { 151 PageProviderService pageProviderService = Framework.getService(PageProviderService.class); 152 Map<String, Serializable> properties = new HashMap<String, Serializable>(); 153 properties.put("coreSession", (Serializable) session); 154 return ((PageProvider<DocumentModel>) pageProviderService.getPageProvider(pageProviderName, null, null, null, 155 properties, parameters)).getCurrentPage(); 156 157 } 158 159 public List<DocumentModel> getSharedSavedSearches(CoreSession session) { 160 return getDocuments(SHARED_SEARCHES_PROVIDER_NAME, session, session.getPrincipal().getName()); 161 } 162 163 @Override 164 @SuppressWarnings("unchecked") 165 public ContentViewState loadSearch(DocumentModel savedSearch) { 166 if (!savedSearch.hasFacet(CONTENT_VIEW_DISPLAY_FACET)) { 167 log.warn(String.format("Search document type %s is missing %s facet", savedSearch.getType(), 168 CONTENT_VIEW_DISPLAY_FACET)); 169 return null; 170 } 171 ContentViewState state = new ContentViewStateImpl(); 172 state.setContentViewName((String) savedSearch.getPropertyValue("cvd:contentViewName")); 173 state.setSearchDocumentModel(savedSearch); 174 state.setSortInfos(getSortInfos(savedSearch)); 175 state.setResultColumns((List<String>) savedSearch.getPropertyValue("cvd:selectedLayoutColumns")); 176 return state; 177 } 178 179 @SuppressWarnings("unchecked") 180 List<SortInfo> getSortInfos(DocumentModel savedSearch) { 181 List<Map<String, Serializable>> list = (List<Map<String, Serializable>>) savedSearch.getPropertyValue( 182 "cvd:sortInfos"); 183 List<SortInfo> sortInfos = new ArrayList<>(); 184 for (Map<String, Serializable> info : list) { 185 sortInfos.add(SortInfo.asSortInfo(info)); 186 } 187 return sortInfos; 188 } 189}