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