/* * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library 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 * Lesser General Public License for more details. * * Contributors: * Anahide Tchertchian */ package org.nuxeo.ecm.webapp.contentbrowser; import static org.jboss.seam.ScopeType.CONVERSATION; import static org.nuxeo.ecm.platform.types.localconfiguration.ContentViewConfigurationConstants.CONTENT_VIEW_CONFIGURATION_CATEGORY; import static org.nuxeo.ecm.platform.types.localconfiguration.ContentViewConfigurationConstants.CONTENT_VIEW_CONFIGURATION_FACET; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Observer; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.localconfiguration.LocalConfigurationService; import org.nuxeo.ecm.platform.actions.Action; import org.nuxeo.ecm.platform.actions.ActionContext; import org.nuxeo.ecm.platform.contentview.jsf.ContentView; import org.nuxeo.ecm.platform.contentview.jsf.ContentViewHeader; import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; import org.nuxeo.ecm.platform.types.adapter.TypeInfo; import org.nuxeo.ecm.platform.types.localconfiguration.ContentViewConfiguration; import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; import org.nuxeo.ecm.platform.ui.web.api.WebActions; import org.nuxeo.ecm.webapp.action.ActionContextProvider; import org.nuxeo.ecm.webapp.helpers.EventNames; import org.nuxeo.runtime.api.Framework; /** * Handles available content views defined on a document type per category, as * well as helper methods to retrieve selection actions for a given content * view. * * @author Anahide Tchertchian * @since 5.4 */ @Name("documentContentViewActions") @Scope(CONVERSATION) public class DocumentContentViewActions implements Serializable { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(DocumentContentViewActions.class); @In(create = true, required = false) protected transient NavigationContext navigationContext; @In(create = true, required = false) protected transient WebActions webActions; @In(create = true, required = false) protected transient ActionContextProvider actionContextProvider; @In(create = true) protected ContentViewService contentViewService; /** * Map caching content views defined on a given document type */ protected Map<String, Map<String, List<ContentViewHeader>>> typeToContentView = new HashMap<String, Map<String, List<ContentViewHeader>>>(); protected Map<String, List<ContentViewHeader>> currentAvailableContentViews; /** * Map caching content views shown in export defined on a given document * type */ protected Map<String, Map<String, List<ContentViewHeader>>> typeToExportContentView = new HashMap<String, Map<String, List<ContentViewHeader>>>(); protected Map<String, List<ContentViewHeader>> currentExportContentViews; // API for content view support protected Map<String, List<ContentViewHeader>> getContentViewHeaders( TypeInfo typeInfo, boolean export) throws ClientException { Map<String, List<ContentViewHeader>> res = new LinkedHashMap<String, List<ContentViewHeader>>(); Map<String, String[]> cvNamesByCat; if (export) { cvNamesByCat = typeInfo.getContentViewsForExport(); } else { cvNamesByCat = typeInfo.getContentViews(); } if (cvNamesByCat != null) { for (Map.Entry<String, String[]> cvNameByCat : cvNamesByCat.entrySet()) { List<ContentViewHeader> headers = new ArrayList<ContentViewHeader>(); String[] cvNames = cvNameByCat.getValue(); if (cvNames != null) { for (String cvName : cvNames) { ContentViewHeader header = contentViewService.getContentViewHeader(cvName); if (header != null) { headers.add(header); } } } res.put(cvNameByCat.getKey(), headers); } } return res; } protected void retrieveContentViewHeaders(DocumentModel doc) throws ClientException { String docType = doc.getType(); if (!typeToContentView.containsKey(docType)) { TypeInfo typeInfo = doc.getAdapter(TypeInfo.class); Map<String, List<ContentViewHeader>> byCategories = getContentViewHeaders( typeInfo, false); typeToContentView.put(docType, byCategories); } } protected void retrieveExportContentViewHeaders(DocumentModel doc) throws ClientException { String docType = doc.getType(); if (!typeToExportContentView.containsKey(docType)) { TypeInfo typeInfo = doc.getAdapter(TypeInfo.class); Map<String, List<ContentViewHeader>> byCategories = getContentViewHeaders( typeInfo, true); typeToExportContentView.put(docType, byCategories); } } /** * Returns true if content views are defined on given document for given * category. * <p> * Also fetches content view headers defined on a document type */ public boolean hasContentViewSupport(DocumentModel doc, String category) throws ClientException { if (doc == null) { return false; } retrieveContentViewHeaders(doc); String docType = doc.getType(); if (!typeToContentView.get(docType).containsKey(category)) { return false; } return !typeToContentView.get(docType).get(category).isEmpty(); } public Map<String, List<ContentViewHeader>> getAvailableContentViewsForDocument( DocumentModel doc) throws ClientException { if (doc == null) { return Collections.emptyMap(); } retrieveContentViewHeaders(doc); String docType = doc.getType(); return typeToContentView.get(docType); } public List<ContentViewHeader> getAvailableContentViewsForDocument( DocumentModel doc, String category) throws ClientException { if (doc == null) { return Collections.emptyList(); } if (CONTENT_VIEW_CONFIGURATION_CATEGORY.equals(category)) { List<ContentViewHeader> localHeaders = getLocalConfiguredContentViews(doc); if (localHeaders != null) { return localHeaders; } } retrieveContentViewHeaders(doc); String docType = doc.getType(); if (!typeToContentView.get(docType).containsKey(category)) { return Collections.emptyList(); } return typeToContentView.get(doc.getType()).get(category); } public Map<String, List<ContentViewHeader>> getAvailableContentViewsForCurrentDocument() throws ClientException { if (currentAvailableContentViews == null) { DocumentModel currentDocument = navigationContext.getCurrentDocument(); currentAvailableContentViews = getAvailableContentViewsForDocument(currentDocument); } return currentAvailableContentViews; } public List<ContentViewHeader> getAvailableContentViewsForCurrentDocument( String category) throws ClientException { if (CONTENT_VIEW_CONFIGURATION_CATEGORY.equals(category)) { DocumentModel currentDoc = navigationContext.getCurrentDocument(); List<ContentViewHeader> localHeaders = getLocalConfiguredContentViews(currentDoc); if (localHeaders != null) { return localHeaders; } } getAvailableContentViewsForCurrentDocument(); return currentAvailableContentViews.get(category); } public List<ContentViewHeader> getLocalConfiguredContentViews( DocumentModel doc) { LocalConfigurationService localConfigurationService; try { localConfigurationService = Framework.getService(LocalConfigurationService.class); if (localConfigurationService == null) { return null; } ContentViewConfiguration configuration = localConfigurationService.getConfiguration( ContentViewConfiguration.class, CONTENT_VIEW_CONFIGURATION_FACET, doc); if (configuration == null) { return null; } List<String> cvNames = configuration.getContentViewsForType(doc.getType()); if (cvNames == null) { return null; } List<ContentViewHeader> headers = new ArrayList<ContentViewHeader>(); for (String cvName : cvNames) { ContentViewHeader header = contentViewService.getContentViewHeader(cvName); if (header != null) { headers.add(header); } } if (!headers.isEmpty()) { return headers; } } catch (Exception e) { log.error("Failed to get local configured ContentViews", e); } return null; } public Map<String, List<ContentViewHeader>> getExportContentViewsForDocument( DocumentModel doc) throws ClientException { if (doc == null) { return Collections.emptyMap(); } retrieveExportContentViewHeaders(doc); String docType = doc.getType(); return typeToExportContentView.get(docType); } public Map<String, List<ContentViewHeader>> getExportContentViewsForCurrentDocument() throws ClientException { if (currentExportContentViews == null) { DocumentModel currentDocument = navigationContext.getCurrentDocument(); currentExportContentViews = getExportContentViewsForDocument(currentDocument); } return currentExportContentViews; } public List<ContentViewHeader> getExportContentViewsForCurrentDocument( String category) throws ClientException { getExportContentViewsForCurrentDocument(); return currentExportContentViews.get(category); } @Observer(value = { EventNames.USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED }, create = false) @BypassInterceptors public void documentChanged() { currentAvailableContentViews = null; currentExportContentViews = null; } /** * Resets typeToContentView cache on {@link EventNames#FLUSH_EVENT}, * triggered by hot reload when dev mode is set. * * @since 5.7.1 */ @Observer(value = { EventNames.FLUSH_EVENT }) @BypassInterceptors public void onHotReloadFlush() { typeToContentView = new HashMap<String, Map<String, List<ContentViewHeader>>>(); } /** * Helper to retrieve selection actions for a given content view, passing * additional variables to the {@link ActionContext} used for resolution. * * @since 2.17 * @param category * @param contentView * @param selectedEntries */ public List<Action> getSelectionActions(String category, ContentView contentView, List<Object> selectedEntries) { ActionContext ctx = actionContextProvider.createActionContext(); ctx.putLocalVariable("contentView", contentView); ctx.putLocalVariable("selectedDocuments", selectedEntries); return webActions.getActionsList(category, ctx, false); } }