001/* 002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Anahide Tchertchian 016 */ 017package org.nuxeo.ecm.platform.contentview.seam; 018 019import static org.jboss.seam.ScopeType.CONVERSATION; 020 021import java.io.Serializable; 022import java.io.UnsupportedEncodingException; 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.List; 026 027import javax.faces.context.FacesContext; 028import javax.faces.model.SelectItem; 029 030import org.jboss.seam.annotations.In; 031import org.jboss.seam.annotations.Name; 032import org.jboss.seam.annotations.Scope; 033import org.jboss.seam.annotations.intercept.BypassInterceptors; 034import org.nuxeo.ecm.core.api.CoreSession; 035import org.nuxeo.ecm.core.api.DocumentModel; 036import org.nuxeo.ecm.core.api.NuxeoPrincipal; 037import org.nuxeo.ecm.core.api.SortInfo; 038import org.nuxeo.ecm.platform.actions.Action; 039import org.nuxeo.ecm.platform.actions.ActionContext; 040import org.nuxeo.ecm.platform.actions.jsf.JSFActionContext; 041import org.nuxeo.ecm.platform.actions.seam.SeamActionContext; 042import org.nuxeo.ecm.platform.contentview.jsf.ContentView; 043import org.nuxeo.ecm.platform.contentview.jsf.ContentViewCache; 044import org.nuxeo.ecm.platform.contentview.jsf.ContentViewService; 045import org.nuxeo.ecm.platform.contentview.jsf.ContentViewState; 046import org.nuxeo.ecm.platform.query.api.PageProvider; 047import org.nuxeo.ecm.platform.ui.web.api.WebActions; 048import org.nuxeo.ecm.platform.ui.web.util.SeamContextHelper; 049 050/** 051 * Handles cache and refresh for named content views. 052 * 053 * @author Anahide Tchertchian 054 * @since 5.4 055 * @since 5.4.2: moved to content-view-jsf module 056 */ 057@Name("contentViewActions") 058@Scope(CONVERSATION) 059public class ContentViewActions implements Serializable { 060 061 private static final long serialVersionUID = 1L; 062 063 @In(create = true) 064 protected ContentViewRestActions contentViewRestActions; 065 066 @In(create = true) 067 protected ContentViewService contentViewService; 068 069 protected final ContentViewCache cache = new ContentViewCache(); 070 071 protected Long globalPageSize; 072 073 @In(create = true) 074 private transient NuxeoPrincipal currentNuxeoPrincipal; 075 076 @In(create = true, required = false) 077 private transient CoreSession documentManager; 078 079 @In(create = true, required = false) 080 protected transient WebActions webActions; 081 082 protected ContentView currentContentView; 083 084 /** 085 * Returns the current global content view. 086 * <p> 087 * Current content view is usually the last one displayed on the page, but this may change depending on calls to 088 * {@link #setCurrentContentView(ContentView)}. 089 */ 090 public ContentView getCurrentContentView() { 091 return currentContentView; 092 } 093 094 /** 095 * Sets the current global content view. 096 * 097 * @see #getCurrentGlobalPageSize() 098 */ 099 public void setCurrentContentView(ContentView cv) { 100 currentContentView = cv; 101 } 102 103 /** 104 * Returns the global page size, or returns the page size on current content view if set. 105 */ 106 public Long getCurrentGlobalPageSize() { 107 if (currentContentView != null && currentContentView.getUseGlobalPageSize()) { 108 return currentContentView.getCurrentPageSize(); 109 } 110 return globalPageSize; 111 } 112 113 /** 114 * Sets the global page size, useful to set the value having the appropriate selection set, see 115 * {@link #getCurrentContentView()} 116 */ 117 public void setCurrentGlobalPageSize(Long pageSize) { 118 globalPageSize = pageSize; 119 } 120 121 /** 122 * Returns the global page size 123 */ 124 public Long getGlobalPageSize() { 125 return globalPageSize; 126 } 127 128 /** 129 * Returns the list of available options for page size selections, for given content view. 130 * <p> 131 * This method relies on a hard-coded set of available values, and adapts it to the current content view page size 132 * and max page size information to present more or less items from this list. 133 * 134 * @since 5.8 135 */ 136 @SuppressWarnings("boxing") 137 public List<SelectItem> getPageSizeOptions(ContentView cv) { 138 List<SelectItem> items = new ArrayList<SelectItem>(); 139 if (cv == null) { 140 return items; 141 } 142 List<Long> values = new ArrayList<Long>(); 143 if (cv.getUseGlobalPageSize()) { 144 // add the global page size if not present 145 Long globalSize = getGlobalPageSize(); 146 if (globalSize != null && globalSize > 0 && !values.contains(globalSize)) { 147 values.add(globalSize); 148 } 149 } 150 long maxPageSize = 0; 151 PageProvider<?> pp = cv.getCurrentPageProvider(); 152 if (pp != null) { 153 // include original page size options set on the page provider definition, as well as current page size if 154 // not present 155 List<Long> options = pp.getPageSizeOptions(); 156 if (options != null) { 157 values.addAll(options); 158 } 159 maxPageSize = pp.getMaxPageSize(); 160 } 161 Collections.sort(values); 162 for (Long value : values) { 163 // remove every element that would be larger than max page size 164 if (maxPageSize > 0 && maxPageSize < value) { 165 break; 166 } 167 items.add(new SelectItem(value)); 168 } 169 // make sure the list is not empty 170 if (items.isEmpty()) { 171 if (maxPageSize > 0) { 172 items.add(new SelectItem(maxPageSize)); 173 } else { 174 items.add(new SelectItem(1)); 175 } 176 } 177 return items; 178 } 179 180 /** 181 * Sets the global page size 182 */ 183 public void setGlobalPageSize(Long pageSize) { 184 globalPageSize = pageSize; 185 } 186 187 public ContentView getContentView(String name) { 188 return getContentView(name, null); 189 } 190 191 /** 192 * Returns content view with given name, or null if no content view with this name is found. 193 * <p> 194 * If parameter searchDocumentModel is not null, it will be set on the content view. If it is null and the content 195 * is using a provider that needs it, a new document model is created and attached to it. This document model is 196 * resolved from the binding put in the content view XML definition, or from the document type in this definition if 197 * no binding is set. 198 * <p> 199 * If not null, this content view is set as the current content view so that subsequent calls to other methods can 200 * take information from it, like {@link #getCurrentGlobalPageSize()} 201 * <p> 202 * 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 203 * changes (if defined). 204 * 205 */ 206 public ContentView getContentView(String name, DocumentModel searchDocumentModel) { 207 ContentView cView = cache.get(name); 208 if (cView == null) { 209 cView = contentViewService.getContentView(name); 210 if (cView != null) { 211 cache.add(cView); 212 } 213 } 214 if (cView != null) { 215 if (searchDocumentModel != null) { 216 cView.setSearchDocumentModel(searchDocumentModel); 217 } 218 setCurrentContentView(cView); 219 } 220 return cView; 221 } 222 223 public ContentView getContentViewWithProvider(String name) { 224 return getContentViewWithProvider(name, null, null, null, null); 225 } 226 227 public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel) 228 { 229 return getContentViewWithProvider(name, searchDocumentModel, null, null, null); 230 } 231 232 public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, 233 List<SortInfo> sortInfos, Long pageSize, Long currentPage) { 234 return getContentViewWithProvider(name, searchDocumentModel, sortInfos, pageSize, currentPage, (Object[]) null); 235 } 236 237 public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, 238 List<SortInfo> sortInfos, Long defaultPageSize, Long pageSize, Long currentPage) { 239 return getContentViewWithProvider(name, searchDocumentModel, sortInfos, defaultPageSize, pageSize, currentPage, 240 (Object[]) null); 241 } 242 243 /** 244 * @since 5.6 245 */ 246 public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, 247 List<SortInfo> sortInfos, Long pageSize, Long currentPage, Object... params) { 248 return getContentViewWithProvider(name, searchDocumentModel, sortInfos, Long.valueOf(-1), pageSize, 249 currentPage, params); 250 } 251 252 /** 253 * Helper method to retrieve a content view, taking care of initialization of page provider according to parameters 254 * and current global page size. 255 * <p> 256 * This method is not public to avoid EL method resolution issues. 257 */ 258 protected ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel, 259 List<SortInfo> sortInfos, Long defaultPageSize, Long pageSize, Long currentPage, Object... params) 260 { 261 ContentView cView = getContentView(name, searchDocumentModel); 262 if (cView != null) { 263 if (cView.getUseGlobalPageSize()) { 264 cView.setCurrentPageSize(globalPageSize); 265 } 266 if (cView.getCurrentPageSize() == null && defaultPageSize != null && defaultPageSize.longValue() >= 0) { 267 cView.setCurrentPageSize(defaultPageSize); 268 } 269 // initialize provider 270 cView.getPageProvider(searchDocumentModel, sortInfos, pageSize, currentPage, params); 271 } 272 return cView; 273 } 274 275 /** 276 * Restore a content view from the given parameters. 277 * <p> 278 * 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 279 * changes (if defined). 280 * 281 * @since 5.7 282 */ 283 public ContentView restoreContentView(String contentViewName, Long currentPage, Long pageSize, 284 List<SortInfo> sortInfos, String jsonContentViewState) throws UnsupportedEncodingException { 285 ContentView cv = contentViewRestActions.restoreContentView(contentViewName, currentPage, pageSize, sortInfos, 286 jsonContentViewState); 287 cache.add(cv); 288 return cv; 289 } 290 291 /** 292 * Restore a Content View from the given ContentView state. 293 * <p> 294 * 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 295 * changes (if defined). 296 * 297 * @since 6.0 298 */ 299 public ContentView restoreContentView(ContentViewState state) throws UnsupportedEncodingException { 300 ContentView cv = contentViewService.restoreContentView(state); 301 cache.add(cv); 302 return cv; 303 } 304 305 /** 306 * Refreshes all content views that have declared the given seam event name as a refresh event in their XML 307 * configuration. 308 */ 309 @BypassInterceptors 310 public void refreshOnSeamEvent(String seamEventName) { 311 cache.refreshOnEvent(seamEventName); 312 } 313 314 /** 315 * Resets all content views page providers that have declared the given seam event name as a reset event in their 316 * XML configuration. 317 */ 318 @BypassInterceptors 319 public void resetPageProviderOnSeamEvent(String seamEventName) { 320 cache.resetPageProviderOnEvent(seamEventName); 321 } 322 323 @BypassInterceptors 324 public void refresh(String contentViewName) { 325 cache.refresh(contentViewName, false); 326 } 327 328 @BypassInterceptors 329 public void refreshAndRewind(String contentViewName) { 330 cache.refresh(contentViewName, true); 331 } 332 333 /** 334 * @since 6.0 335 */ 336 @BypassInterceptors 337 public void resetAggregates(String contentViewName) { 338 cache.resetPageProviderAggregates(contentViewName); 339 } 340 341 @BypassInterceptors 342 public void resetPageProvider(String contentViewName) { 343 cache.resetPageProvider(contentViewName); 344 } 345 346 @BypassInterceptors 347 public void reset(String contentViewName) { 348 cache.reset(contentViewName); 349 } 350 351 @BypassInterceptors 352 public void resetAllContent() { 353 cache.resetAllContent(); 354 } 355 356 @BypassInterceptors 357 public void resetAll() { 358 cache.resetAll(); 359 } 360 361 /** 362 * @since 5.7 363 */ 364 @BypassInterceptors 365 public void refreshAll() { 366 cache.refreshAll(); 367 } 368 369 /** 370 * @since 5.7 371 */ 372 @BypassInterceptors 373 public void refreshAndRewindAll() { 374 cache.refreshAndRewindAll(); 375 } 376 377 /** 378 * Returns actions filtered depending on given custom context. 379 * <p> 380 * Boolean values are declared as objects to avoid conversion to "false" when variable is not defined, and keep 381 * "null" value. 382 * 383 * @since 6.0 384 */ 385 public List<Action> getActionsList(String category, DocumentModel currentDocument, ContentView contentView, 386 Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, 387 Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, 388 Object showSpreadsheet) { 389 return webActions.getActionsList( 390 category, 391 createContentViewActionContext(currentDocument, contentView, showPageSizeSelector, showRefreshCommand, 392 showCSVExport, showPDFExport, showSyndicationLinks, showSlideshow, showEditColumns, 393 showEditRows, showSpreadsheet)); 394 } 395 396 protected ActionContext createContentViewActionContext(DocumentModel currentDocument, ContentView contentView, 397 Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, 398 Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, 399 Object showSpreadsheet) { 400 ActionContext ctx; 401 FacesContext faces = FacesContext.getCurrentInstance(); 402 if (faces == null) { 403 ctx = new SeamActionContext(); 404 } else { 405 ctx = new JSFActionContext(faces); 406 } 407 ctx.setCurrentPrincipal(currentNuxeoPrincipal); 408 ctx.setDocumentManager(documentManager); 409 ctx.setCurrentDocument(currentDocument); 410 ctx.putLocalVariable("SeamContext", new SeamContextHelper()); 411 ctx.putLocalVariable("contentView", contentView); 412 // additional local variables for action filters 413 ctx.putLocalVariable("showPageSizeSelector", showPageSizeSelector); 414 ctx.putLocalVariable("showRefreshCommand", showRefreshCommand); 415 ctx.putLocalVariable("showCSVExport", showCSVExport); 416 ctx.putLocalVariable("showPDFExport", showPDFExport); 417 ctx.putLocalVariable("showSyndicationLinks", showSyndicationLinks); 418 ctx.putLocalVariable("showSlideshow", showSlideshow); 419 ctx.putLocalVariable("showEditColumns", showEditColumns); 420 ctx.putLocalVariable("showEditRows", showEditRows); 421 ctx.putLocalVariable("showSpreadsheet", showSpreadsheet); 422 return ctx; 423 } 424}