/* * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Anahide Tchertchian */ package org.nuxeo.ecm.platform.contentview.seam; import static org.jboss.seam.ScopeType.CONVERSATION; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.faces.context.FacesContext; import javax.faces.model.SelectItem; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.NuxeoPrincipal; import org.nuxeo.ecm.core.api.SortInfo; import org.nuxeo.ecm.platform.actions.Action; import org.nuxeo.ecm.platform.actions.ActionContext; import org.nuxeo.ecm.platform.actions.jsf.JSFActionContext; import org.nuxeo.ecm.platform.actions.seam.SeamActionContext; import org.nuxeo.ecm.platform.contentview.jsf.ContentView; import org.nuxeo.ecm.platform.contentview.jsf.ContentViewCache; import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; import org.nuxeo.ecm.platform.query.api.PageProvider; import org.nuxeo.ecm.platform.ui.web.api.WebActions; import org.nuxeo.ecm.platform.ui.web.util.SeamContextHelper; /** * Handles cache and refresh for named content views. * * @author Anahide Tchertchian * @since 5.4 * @since 5.4.2: moved to content-view-jsf module */ @Name("contentViewActions") @Scope(CONVERSATION) public class ContentViewActions implements Serializable { private static final long serialVersionUID = 1L; @In(create = true) protected ContentViewRestActions contentViewRestActions; @In(create = true) protected ContentViewService contentViewService; protected final ContentViewCache cache = new ContentViewCache(); protected Long globalPageSize; @In(create = true) private transient NuxeoPrincipal currentNuxeoPrincipal; @In(create = true, required = false) private transient CoreSession documentManager; @In(create = true, required = false) protected transient WebActions webActions; protected ContentView currentContentView; /** * Returns the current global content view. * <p> * Current content view is usually the last one displayed on the page, but this may change depending on calls to * {@link #setCurrentContentView(ContentView)}. */ public ContentView getCurrentContentView() { return currentContentView; } /** * Sets the current global content view. * * @see #getCurrentGlobalPageSize() */ public void setCurrentContentView(ContentView cv) { currentContentView = cv; } /** * Returns the global page size, or returns the page size on current content view if set. */ public Long getCurrentGlobalPageSize() { if (currentContentView != null && currentContentView.getUseGlobalPageSize()) { return currentContentView.getCurrentPageSize(); } return globalPageSize; } /** * Sets the global page size, useful to set the value having the appropriate selection set, see * {@link #getCurrentContentView()} */ public void setCurrentGlobalPageSize(Long pageSize) { globalPageSize = pageSize; } /** * Returns the global page size */ public Long getGlobalPageSize() { return globalPageSize; } /** * Returns the list of available options for page size selections, for given content view. * <p> * This method relies on a hard-coded set of available values, and adapts it to the current content view page size * and max page size information to present more or less items from this list. * * @since 5.8 */ @SuppressWarnings("boxing") public List<SelectItem> getPageSizeOptions(ContentView cv) { List<SelectItem> items = new ArrayList<SelectItem>(); if (cv == null) { return items; } List<Long> values = new ArrayList<Long>(); long maxPageSize = 0; PageProvider<?> pp = cv.getCurrentPageProvider(); if (pp != null) { // include original page size options set on the page provider definition, as well as current page size if // not present List<Long> options = pp.getPageSizeOptions(); if (options != null) { values.addAll(options); } maxPageSize = pp.getMaxPageSize(); } if (cv.getUseGlobalPageSize()) { // add the global page size if not present Long globalSize = getGlobalPageSize(); if (globalSize != null && globalSize > 0 && !values.contains(globalSize)) { values.add(globalSize); } } Collections.sort(values); for (Long value : values) { // remove every element that would be larger than max page size if (maxPageSize > 0 && maxPageSize < value) { break; } items.add(new SelectItem(value)); } // make sure the list is not empty if (items.isEmpty()) { if (maxPageSize > 0) { items.add(new SelectItem(maxPageSize)); } else { items.add(new SelectItem(1)); } } return items; } /** * Sets the global page size */ public void setGlobalPageSize(Long pageSize) { globalPageSize = pageSize; } public ContentView getContentView(String name) { return getContentView(name, null); } /** * Returns content view with given name, or null if no content view with this name is found. * <p> * If parameter searchDocumentModel is not null, it will be set on the content view. If it is null and the content * is using a provider that needs it, a new document model is created and attached to it. This document model is * resolved from the binding put in the content view XML definition, or from the document type in this definition if * no binding is set. * <p> * If not null, this content view is set as the current content view so that subsequent calls to other methods can * take information from it, like {@link #getCurrentGlobalPageSize()} * <p> * The content view is put in a cache map so that it's not rebuilt at each call. It is rebuilt when its cache key * changes (if defined). */ public ContentView getContentView(String name, DocumentModel searchDocumentModel) { ContentView cView = cache.get(name); if (cView == null) { cView = contentViewService.getContentView(name); if (cView != null) { cache.add(cView); } } if (cView != null) { if (searchDocumentModel != null) { cView.setSearchDocumentModel(searchDocumentModel); } setCurrentContentView(cView); } return cView; } public ContentView getContentViewWithProvider(String name) { return getContentViewWithProvider(name, null, null, null, null); } public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel) { return getContentViewWithProvider(name, searchDocumentModel, null, null, null); } public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, List<SortInfo> sortInfos, Long pageSize, Long currentPage) { return getContentViewWithProvider(name, searchDocumentModel, sortInfos, pageSize, currentPage, (Object[]) null); } public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, List<SortInfo> sortInfos, Long defaultPageSize, Long pageSize, Long currentPage) { return getContentViewWithProvider(name, searchDocumentModel, sortInfos, defaultPageSize, pageSize, currentPage, (Object[]) null); } /** * @since 5.6 */ public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, List<SortInfo> sortInfos, Long pageSize, Long currentPage, Object... params) { return getContentViewWithProvider(name, searchDocumentModel, sortInfos, Long.valueOf(-1), pageSize, currentPage, params); } /** * Helper method to retrieve a content view, taking care of initialization of page provider according to parameters * and current global page size. * <p> * This method is not public to avoid EL method resolution issues. */ protected ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, List<SortInfo> sortInfos, Long defaultPageSize, Long pageSize, Long currentPage, Object... params) { ContentView cView = getContentView(name, searchDocumentModel); if (cView != null) { if (cView.getUseGlobalPageSize()) { cView.setCurrentPageSize(globalPageSize); } if (cView.getCurrentPageSize() == null && defaultPageSize != null && defaultPageSize.longValue() >= 0) { cView.setCurrentPageSize(defaultPageSize); } // initialize provider cView.getPageProvider(searchDocumentModel, sortInfos, pageSize, currentPage, params); } return cView; } /** * Restore a content view from the given parameters. * <p> * The content view is put in a cache map so that it's not rebuilt at each call. It is rebuilt when its cache key * changes (if defined). * * @since 5.7 */ public ContentView restoreContentView(String contentViewName, Long currentPage, Long pageSize, List<SortInfo> sortInfos, String jsonContentViewState) throws UnsupportedEncodingException { ContentView cv = contentViewRestActions.restoreContentView(contentViewName, currentPage, pageSize, sortInfos, jsonContentViewState); cache.add(cv); return cv; } /** * Restore a Content View from the given ContentView state. * <p> * The content view is put in a cache map so that it's not rebuilt at each call. It is rebuilt when its cache key * changes (if defined). * * @since 6.0 */ public ContentView restoreContentView(ContentViewState state) throws UnsupportedEncodingException { ContentView cv = contentViewService.restoreContentView(state); cache.add(cv); return cv; } /** * Refreshes all content views that have declared the given seam event name as a refresh event in their XML * configuration. */ @BypassInterceptors public void refreshOnSeamEvent(String seamEventName) { cache.refreshOnEvent(seamEventName); } /** * Resets all content views page providers that have declared the given seam event name as a reset event in their * XML configuration. */ @BypassInterceptors public void resetPageProviderOnSeamEvent(String seamEventName) { cache.resetPageProviderOnEvent(seamEventName); } @BypassInterceptors public void refresh(String contentViewName) { cache.refresh(contentViewName, false); } @BypassInterceptors public void refreshAndRewind(String contentViewName) { cache.refresh(contentViewName, true); } /** * @since 6.0 */ @BypassInterceptors public void resetAggregates(String contentViewName) { cache.resetPageProviderAggregates(contentViewName); } @BypassInterceptors public void resetPageProvider(String contentViewName) { cache.resetPageProvider(contentViewName); } @BypassInterceptors public void reset(String contentViewName) { cache.reset(contentViewName); } @BypassInterceptors public void resetAllContent() { cache.resetAllContent(); } @BypassInterceptors public void resetAll() { cache.resetAll(); } /** * @since 5.7 */ @BypassInterceptors public void refreshAll() { cache.refreshAll(); } /** * @since 5.7 */ @BypassInterceptors public void refreshAndRewindAll() { cache.refreshAndRewindAll(); } /** * Returns actions filtered depending on given custom context. * <p> * Boolean values are declared as objects to avoid conversion to "false" when variable is not defined, and keep * "null" value. * * @since 6.0 */ public List<Action> getActionsList(String category, DocumentModel currentDocument, ContentView contentView, Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, Object showSpreadsheet) { return webActions.getActionsList(category, createContentViewActionContext(currentDocument, contentView, showPageSizeSelector, showRefreshCommand, showCSVExport, showPDFExport, showSyndicationLinks, showSlideshow, showEditColumns, showEditRows, showSpreadsheet)); } protected ActionContext createContentViewActionContext(DocumentModel currentDocument, ContentView contentView, Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, Object showSpreadsheet) { ActionContext ctx; FacesContext faces = FacesContext.getCurrentInstance(); if (faces == null) { ctx = new SeamActionContext(); } else { ctx = new JSFActionContext(faces); } ctx.setCurrentPrincipal(currentNuxeoPrincipal); ctx.setDocumentManager(documentManager); ctx.setCurrentDocument(currentDocument); ctx.putLocalVariable("SeamContext", new SeamContextHelper()); ctx.putLocalVariable("contentView", contentView); // additional local variables for action filters ctx.putLocalVariable("showPageSizeSelector", showPageSizeSelector); ctx.putLocalVariable("showRefreshCommand", showRefreshCommand); ctx.putLocalVariable("showCSVExport", showCSVExport); ctx.putLocalVariable("showPDFExport", showPDFExport); ctx.putLocalVariable("showSyndicationLinks", showSyndicationLinks); ctx.putLocalVariable("showSlideshow", showSlideshow); ctx.putLocalVariable("showEditColumns", showEditColumns); ctx.putLocalVariable("showEditRows", showEditRows); ctx.putLocalVariable("showSpreadsheet", showSpreadsheet); return ctx; } }