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 long maxPageSize = 0; 146 PageProvider<?> pp = cv.getCurrentPageProvider(); 147 if (pp != null) { 148 // include original page size options set on the page provider definition, as well as current page size if 149 // not present 150 List<Long> options = pp.getPageSizeOptions(); 151 if (options != null) { 152 values.addAll(options); 153 } 154 maxPageSize = pp.getMaxPageSize(); 155 } 156 if (cv.getUseGlobalPageSize()) { 157 // add the global page size if not present 158 Long globalSize = getGlobalPageSize(); 159 if (globalSize != null && globalSize > 0 && !values.contains(globalSize)) { 160 values.add(globalSize); 161 } 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 public ContentView getContentView(String name, DocumentModel searchDocumentModel) { 208 ContentView cView = cache.get(name); 209 if (cView == null) { 210 cView = contentViewService.getContentView(name); 211 if (cView != null) { 212 cache.add(cView); 213 } 214 } 215 if (cView != null) { 216 if (searchDocumentModel != null) { 217 cView.setSearchDocumentModel(searchDocumentModel); 218 } 219 setCurrentContentView(cView); 220 } 221 return cView; 222 } 223 224 public ContentView getContentViewWithProvider(String name) { 225 return getContentViewWithProvider(name, null, null, null, null); 226 } 227 228 public ContentView getContentViewWithProvider(String name, DocumentModel searchDocumentModel) { 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, currentPage, 249 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 ContentView cView = getContentView(name, searchDocumentModel); 261 if (cView != null) { 262 if (cView.getUseGlobalPageSize()) { 263 cView.setCurrentPageSize(globalPageSize); 264 } 265 if (cView.getCurrentPageSize() == null && defaultPageSize != null && defaultPageSize.longValue() >= 0) { 266 cView.setCurrentPageSize(defaultPageSize); 267 } 268 // initialize provider 269 cView.getPageProvider(searchDocumentModel, sortInfos, pageSize, currentPage, params); 270 } 271 return cView; 272 } 273 274 /** 275 * Restore a content view from the given parameters. 276 * <p> 277 * 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 278 * changes (if defined). 279 * 280 * @since 5.7 281 */ 282 public ContentView restoreContentView(String contentViewName, Long currentPage, Long pageSize, 283 List<SortInfo> sortInfos, String jsonContentViewState) throws UnsupportedEncodingException { 284 ContentView cv = contentViewRestActions.restoreContentView(contentViewName, currentPage, pageSize, sortInfos, 285 jsonContentViewState); 286 cache.add(cv); 287 return cv; 288 } 289 290 /** 291 * Restore a Content View from the given ContentView state. 292 * <p> 293 * 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 294 * changes (if defined). 295 * 296 * @since 6.0 297 */ 298 public ContentView restoreContentView(ContentViewState state) throws UnsupportedEncodingException { 299 ContentView cv = contentViewService.restoreContentView(state); 300 cache.add(cv); 301 return cv; 302 } 303 304 /** 305 * Refreshes all content views that have declared the given seam event name as a refresh event in their XML 306 * configuration. 307 */ 308 @BypassInterceptors 309 public void refreshOnSeamEvent(String seamEventName) { 310 cache.refreshOnEvent(seamEventName); 311 } 312 313 /** 314 * Resets all content views page providers that have declared the given seam event name as a reset event in their 315 * XML configuration. 316 */ 317 @BypassInterceptors 318 public void resetPageProviderOnSeamEvent(String seamEventName) { 319 cache.resetPageProviderOnEvent(seamEventName); 320 } 321 322 @BypassInterceptors 323 public void refresh(String contentViewName) { 324 cache.refresh(contentViewName, false); 325 } 326 327 @BypassInterceptors 328 public void refreshAndRewind(String contentViewName) { 329 cache.refresh(contentViewName, true); 330 } 331 332 /** 333 * @since 6.0 334 */ 335 @BypassInterceptors 336 public void resetAggregates(String contentViewName) { 337 cache.resetPageProviderAggregates(contentViewName); 338 } 339 340 @BypassInterceptors 341 public void resetPageProvider(String contentViewName) { 342 cache.resetPageProvider(contentViewName); 343 } 344 345 @BypassInterceptors 346 public void reset(String contentViewName) { 347 cache.reset(contentViewName); 348 } 349 350 @BypassInterceptors 351 public void resetAllContent() { 352 cache.resetAllContent(); 353 } 354 355 @BypassInterceptors 356 public void resetAll() { 357 cache.resetAll(); 358 } 359 360 /** 361 * @since 5.7 362 */ 363 @BypassInterceptors 364 public void refreshAll() { 365 cache.refreshAll(); 366 } 367 368 /** 369 * @since 5.7 370 */ 371 @BypassInterceptors 372 public void refreshAndRewindAll() { 373 cache.refreshAndRewindAll(); 374 } 375 376 /** 377 * Returns actions filtered depending on given custom context. 378 * <p> 379 * Boolean values are declared as objects to avoid conversion to "false" when variable is not defined, and keep 380 * "null" value. 381 * 382 * @since 6.0 383 */ 384 public List<Action> getActionsList(String category, DocumentModel currentDocument, ContentView contentView, 385 Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, 386 Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, 387 Object showSpreadsheet) { 388 return webActions.getActionsList(category, 389 createContentViewActionContext(currentDocument, contentView, showPageSizeSelector, showRefreshCommand, 390 showCSVExport, showPDFExport, showSyndicationLinks, showSlideshow, showEditColumns, 391 showEditRows, showSpreadsheet)); 392 } 393 394 protected ActionContext createContentViewActionContext(DocumentModel currentDocument, ContentView contentView, 395 Object showPageSizeSelector, Object showRefreshCommand, Object showCSVExport, Object showPDFExport, 396 Object showSyndicationLinks, Object showSlideshow, Object showEditColumns, Object showEditRows, 397 Object showSpreadsheet) { 398 ActionContext ctx; 399 FacesContext faces = FacesContext.getCurrentInstance(); 400 if (faces == null) { 401 ctx = new SeamActionContext(); 402 } else { 403 ctx = new JSFActionContext(faces); 404 } 405 ctx.setCurrentPrincipal(currentNuxeoPrincipal); 406 ctx.setDocumentManager(documentManager); 407 ctx.setCurrentDocument(currentDocument); 408 ctx.putLocalVariable("SeamContext", new SeamContextHelper()); 409 ctx.putLocalVariable("contentView", contentView); 410 // additional local variables for action filters 411 ctx.putLocalVariable("showPageSizeSelector", showPageSizeSelector); 412 ctx.putLocalVariable("showRefreshCommand", showRefreshCommand); 413 ctx.putLocalVariable("showCSVExport", showCSVExport); 414 ctx.putLocalVariable("showPDFExport", showPDFExport); 415 ctx.putLocalVariable("showSyndicationLinks", showSyndicationLinks); 416 ctx.putLocalVariable("showSlideshow", showSlideshow); 417 ctx.putLocalVariable("showEditColumns", showEditColumns); 418 ctx.putLocalVariable("showEditRows", showEditRows); 419 ctx.putLocalVariable("showSpreadsheet", showSpreadsheet); 420 return ctx; 421 } 422}