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.jsf; 020 021import static org.apache.commons.lang.StringUtils.isBlank; 022 023import java.util.ArrayList; 024import java.util.List; 025import java.util.Map; 026 027import javax.faces.context.ExternalContext; 028import javax.faces.context.FacesContext; 029 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.jboss.seam.core.Events; 034import org.nuxeo.ecm.core.api.DocumentModel; 035import org.nuxeo.ecm.core.api.DocumentModelFactory; 036import org.nuxeo.ecm.core.api.PropertyException; 037import org.nuxeo.ecm.core.api.SortInfo; 038import org.nuxeo.ecm.core.api.model.impl.MapProperty; 039import org.nuxeo.ecm.platform.query.api.Aggregate; 040import org.nuxeo.ecm.platform.query.api.PageProvider; 041import org.nuxeo.ecm.platform.query.api.PageProviderChangedListener; 042import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils; 043import org.nuxeo.runtime.api.Framework; 044 045import com.google.common.base.Function; 046 047/** 048 * Default implementation for the content view object. 049 * <p> 050 * Provides simple getters for attributes defined in the XMap descriptor, except cache key which is computed from 051 * currrent {@link FacesContext} instance if cache key is an EL expression. 052 * <p> 053 * The page provider is initialized calling {@link ContentViewService#getPageProvider}. 054 * 055 * @author Anahide Tchertchian 056 * @since 5.4 057 */ 058public class ContentViewImpl implements ContentView, PageProviderChangedListener { 059 060 private static final long serialVersionUID = 1L; 061 062 private static final Log log = LogFactory.getLog(ContentViewImpl.class); 063 064 protected String name; 065 066 protected PageProvider<?> pageProvider; 067 068 protected String title; 069 070 protected boolean translateTitle; 071 072 protected String emptySentence; 073 074 protected boolean translateEmptySentence; 075 076 protected String iconPath; 077 078 protected boolean showTitle; 079 080 protected String selectionList; 081 082 protected String pagination; 083 084 protected List<String> actionCategories; 085 086 protected ContentViewLayout searchLayout; 087 088 protected List<ContentViewLayout> resultLayouts; 089 090 protected List<String> flags; 091 092 protected boolean currentResultLayoutSet = false; 093 094 protected ContentViewLayout currentResultLayout; 095 096 protected List<String> currentResultLayoutColumns; 097 098 protected String cacheKey; 099 100 protected Integer cacheSize; 101 102 protected List<String> refreshEventNames; 103 104 protected List<String> resetEventNames; 105 106 protected boolean useGlobalPageSize; 107 108 protected boolean showPageSizeSelector; 109 110 protected boolean showRefreshCommand; 111 112 protected boolean showFilterForm; 113 114 protected Long currentPageSize; 115 116 protected String[] queryParameters; 117 118 protected DocumentModel searchDocumentModel; 119 120 protected String searchDocumentModelBinding; 121 122 protected String searchDocumentModelType; 123 124 protected String resultColumnsBinding; 125 126 protected String resultLayoutBinding; 127 128 protected String pageSizeBinding; 129 130 protected String sortInfosBinding; 131 132 protected boolean waitForExecution = false; 133 134 protected String waitForExecutionSentence; 135 136 protected boolean executed = false; 137 138 public ContentViewImpl(String name, String title, boolean translateTitle, String iconPath, String selectionList, 139 String pagination, List<String> actionCategories, ContentViewLayout searchLayout, 140 List<ContentViewLayout> resultLayouts, List<String> flags, String cacheKey, Integer cacheSize, 141 List<String> refreshEventNames, List<String> resetEventNames, boolean useGlobalPageSize, 142 String[] queryParameters, String searchDocumentModelBinding, String searchDocumentModelType, 143 String resultColumnsBinding, String resultLayoutBinding, String sortInfosBinding, String pageSizeBinding, 144 boolean showTitle, boolean showPageSizeSelector, boolean showRefreshCommand, boolean showFilterForm, 145 String emptySentence, boolean translateEmptySentence) { 146 this.name = name; 147 this.title = title; 148 this.translateTitle = translateTitle; 149 this.iconPath = iconPath; 150 this.selectionList = selectionList; 151 this.pagination = pagination; 152 this.actionCategories = actionCategories; 153 this.searchLayout = searchLayout; 154 this.resultLayouts = resultLayouts; 155 this.flags = flags; 156 this.cacheKey = cacheKey; 157 this.cacheSize = cacheSize; 158 if (cacheSize != null && cacheSize.intValue() <= 0) { 159 // force a static cache key 160 this.cacheKey = "static_key_no_cache"; 161 } 162 this.refreshEventNames = refreshEventNames; 163 this.resetEventNames = resetEventNames; 164 this.useGlobalPageSize = useGlobalPageSize; 165 this.queryParameters = queryParameters; 166 this.searchDocumentModelBinding = searchDocumentModelBinding; 167 this.searchDocumentModelType = searchDocumentModelType; 168 this.resultColumnsBinding = resultColumnsBinding; 169 this.resultLayoutBinding = resultLayoutBinding; 170 this.pageSizeBinding = pageSizeBinding; 171 this.sortInfosBinding = sortInfosBinding; 172 this.showTitle = showTitle; 173 this.showPageSizeSelector = showPageSizeSelector; 174 this.showRefreshCommand = showRefreshCommand; 175 this.showFilterForm = showFilterForm; 176 this.emptySentence = emptySentence; 177 this.translateEmptySentence = translateEmptySentence; 178 } 179 180 @Override 181 public String getName() { 182 return name; 183 } 184 185 @Override 186 public String getTitle() { 187 return title; 188 } 189 190 @Override 191 public boolean getTranslateTitle() { 192 return translateTitle; 193 } 194 195 @Override 196 public String getIconPath() { 197 return iconPath; 198 } 199 200 @Override 201 public String getSelectionListName() { 202 return selectionList; 203 } 204 205 @Override 206 public String getPagination() { 207 return pagination; 208 } 209 210 @Override 211 public List<String> getActionsCategories() { 212 return actionCategories; 213 } 214 215 @Override 216 public ContentViewLayout getSearchLayout() { 217 return searchLayout; 218 } 219 220 @Override 221 public List<ContentViewLayout> getResultLayouts() { 222 return resultLayouts; 223 } 224 225 @Override 226 public ContentViewLayout getCurrentResultLayout() { 227 // resolve binding if it is set 228 if (!currentResultLayoutSet && !StringUtils.isBlank(resultLayoutBinding)) { 229 Object res = resolveWithSearchDocument(new Function<FacesContext, Object>() { 230 @Override 231 public Object apply(FacesContext ctx) { 232 return ComponentTagUtils.resolveElExpression(ctx, resultLayoutBinding); 233 } 234 }); 235 if (res != null && res instanceof String) { 236 setCurrentResultLayout((String) res); 237 currentResultLayoutSet = true; 238 } 239 } 240 if (currentResultLayout == null && resultLayouts != null && !resultLayouts.isEmpty()) { 241 // resolve first current result layout 242 return resultLayouts.get(0); 243 } 244 return currentResultLayout; 245 } 246 247 @Override 248 public void setCurrentResultLayout(final ContentViewLayout layout) { 249 setCurrentResultLayout(layout, true); 250 } 251 252 public void setCurrentResultLayout(final ContentViewLayout layout, boolean resetLayoutColumn) { 253 if (!isBlank(resultLayoutBinding) && ComponentTagUtils.isStrictValueReference(resultLayoutBinding)) { 254 resolveWithSearchDocument(new Function<FacesContext, Object>() { 255 @Override 256 public Object apply(FacesContext ctx) { 257 ComponentTagUtils.applyValueExpression(ctx, resultLayoutBinding, 258 layout == null ? null : layout.getName()); 259 return null; 260 } 261 }); 262 } 263 // still set current result layout value 264 currentResultLayoutSet = true; 265 currentResultLayout = layout; 266 267 if (resetLayoutColumn) { 268 // reset corresponding columns 269 setCurrentResultLayoutColumns(null); 270 } 271 } 272 273 protected Object resolveWithSearchDocument(Function<FacesContext, Object> func) { 274 FacesContext ctx = FacesContext.getCurrentInstance(); 275 if (getSearchDocumentModel() == null) { 276 return func.apply(ctx); 277 } else { 278 Object previousSearchDocValue = addSearchDocumentToELContext(ctx); 279 try { 280 return func.apply(ctx); 281 } finally { 282 removeSearchDocumentFromELContext(ctx, previousSearchDocValue); 283 } 284 } 285 } 286 287 @Override 288 public void setCurrentResultLayout(String resultLayoutName) { 289 if (resultLayoutName != null) { 290 for (ContentViewLayout layout : resultLayouts) { 291 if (resultLayoutName.equals(layout.getName())) { 292 setCurrentResultLayout(layout, false); 293 } 294 } 295 } 296 } 297 298 @Override 299 public boolean hasResultLayoutBinding() { 300 return !isBlank(resultLayoutBinding); 301 } 302 303 /** 304 * Returns cached page provider if it exists or build a new one if parameters have changed. 305 * <p> 306 * The search document, current page and page size are set on the page provider anyway. Sort infos are not set again 307 * if page provider was not built again (e.g if parameters did not change) to avoid erasing sort infos already held 308 * by it. 309 */ 310 @Override 311 public PageProvider<?> getPageProvider(DocumentModel searchDocument, List<SortInfo> sortInfos, Long pageSize, 312 Long currentPage, Object... params) { 313 // do not return any page provider if filter has not been done yet 314 if (isWaitForExecution() && !isExecuted()) { 315 return null; 316 } 317 318 // resolve search doc so that it can be used in EL expressions defined 319 // in XML configuration 320 boolean setSearchDoc = false; 321 DocumentModel finalSearchDocument = null; 322 if (searchDocument != null) { 323 setSearchDoc = true; 324 finalSearchDocument = searchDocument; 325 } else if (searchDocumentModel == null) { 326 setSearchDoc = true; 327 if (pageProvider != null) { 328 // try to retrieve it on current page provider 329 finalSearchDocument = pageProvider.getSearchDocumentModel(); 330 } 331 if (finalSearchDocument == null) { 332 // initialize it and set it => do not need to set it again 333 finalSearchDocument = getSearchDocumentModel(); 334 setSearchDoc = false; 335 } 336 } else { 337 finalSearchDocument = searchDocumentModel; 338 } 339 if (setSearchDoc) { 340 // set it on content view so that it can be used when resolving EL 341 // expressions 342 setSearchDocumentModel(finalSearchDocument); 343 } 344 345 // fallback on local parameters if defined in the XML configuration 346 if (params == null) { 347 params = getQueryParameters(); 348 } 349 if (sortInfos == null) { 350 sortInfos = resolveSortInfos(); 351 } 352 // allow to pass negative integers instead of null: EL transforms 353 // numbers into value 0 for numbers 354 if (pageSize != null && pageSize.longValue() < 0) { 355 pageSize = null; 356 } 357 if (currentPage != null && currentPage.longValue() < 0) { 358 currentPage = null; 359 } 360 if (pageSize == null) { 361 if (currentPageSize != null && currentPageSize.longValue() >= 0) { 362 pageSize = currentPageSize; 363 } 364 if (pageSize == null) { 365 pageSize = resolvePageSize(); 366 } 367 } 368 369 // parameters changed => reset provider. 370 // do not force setting of sort infos as they can be set directly on 371 // the page provider and this method will be called after so they could 372 // be lost. 373 if (pageProvider == null || pageProvider.hasChangedParameters(params)) { 374 // make the service build the provider 375 ContentViewService service = Framework.getLocalService(ContentViewService.class); 376 pageProvider = service.getPageProvider(getName(), sortInfos, pageSize, currentPage, finalSearchDocument, 377 params); 378 } else { 379 if (pageSize != null) { 380 pageProvider.setPageSize(pageSize.longValue()); 381 } 382 if (currentPage != null) { 383 pageProvider.setCurrentPage(currentPage.longValue()); 384 } 385 } 386 387 // Register listener to be notified when the page has changed on the 388 // page provider 389 pageProvider.setPageProviderChangedListener(this); 390 return pageProvider; 391 } 392 393 @Override 394 public PageProvider<?> getPageProviderWithParams(Object... params) { 395 return getPageProvider(null, null, null, null, params); 396 } 397 398 @Override 399 public PageProvider<?> getPageProvider() { 400 return getPageProviderWithParams((Object[]) null); 401 } 402 403 @Override 404 public PageProvider<?> getCurrentPageProvider() { 405 return pageProvider; 406 } 407 408 @Override 409 public void resetPageProvider() { 410 pageProvider = null; 411 } 412 413 @Override 414 public void refreshPageProvider() { 415 if (pageProvider != null) { 416 pageProvider.refresh(); 417 } 418 setExecuted(true); 419 } 420 421 @Override 422 public void refreshAndRewindPageProvider() { 423 if (pageProvider != null) { 424 pageProvider.refresh(); 425 pageProvider.firstPage(); 426 } 427 setExecuted(true); 428 } 429 430 @Override 431 public String getCacheKey() { 432 FacesContext context = FacesContext.getCurrentInstance(); 433 Object value = ComponentTagUtils.resolveElExpression(context, cacheKey); 434 if (value != null && !(value instanceof String)) { 435 log.error("Error processing expression '" + cacheKey + "', result is not a String: " + value); 436 } 437 return (String) value; 438 } 439 440 @Override 441 public Integer getCacheSize() { 442 return cacheSize; 443 } 444 445 @Override 446 public Object[] getQueryParameters() { 447 if (queryParameters == null) { 448 return null; 449 } 450 FacesContext context = FacesContext.getCurrentInstance(); 451 Object previousSearchDocValue = addSearchDocumentToELContext(context); 452 try { 453 Object[] res = new Object[queryParameters.length]; 454 for (int i = 0; i < queryParameters.length; i++) { 455 res[i] = ComponentTagUtils.resolveElExpression(context, queryParameters[i]); 456 } 457 return res; 458 } finally { 459 removeSearchDocumentFromELContext(context, previousSearchDocValue); 460 } 461 } 462 463 @Override 464 public List<String> getRefreshEventNames() { 465 return refreshEventNames; 466 } 467 468 @Override 469 public List<String> getResetEventNames() { 470 return resetEventNames; 471 } 472 473 @Override 474 public boolean getUseGlobalPageSize() { 475 return useGlobalPageSize; 476 } 477 478 @Override 479 public Long getCurrentPageSize() { 480 // take actual value on page provider first in case it's reached its 481 // max page size 482 if (pageProvider != null) { 483 long pageSize = pageProvider.getPageSize(); 484 long maxPageSize = pageProvider.getMaxPageSize(); 485 if (pageSize > 0 && maxPageSize > 0 && maxPageSize < pageSize) { 486 return Long.valueOf(maxPageSize); 487 } 488 return Long.valueOf(pageSize); 489 } 490 if (currentPageSize != null && currentPageSize.longValue() >= 0) { 491 return currentPageSize; 492 } 493 return null; 494 } 495 496 @Override 497 public void setCurrentPageSize(Long pageSize) { 498 currentPageSize = pageSize; 499 raiseEvent(CONTENT_VIEW_PAGE_SIZE_CHANGED_EVENT); 500 } 501 502 @Override 503 public DocumentModel getSearchDocumentModel() { 504 if (searchDocumentModel == null) { 505 if (searchDocumentModelBinding != null) { 506 // initialize from binding 507 FacesContext context = FacesContext.getCurrentInstance(); 508 Object value = ComponentTagUtils.resolveElExpression(context, searchDocumentModelBinding); 509 if (value != null && !(value instanceof DocumentModel)) { 510 log.error("Error processing expression '" + searchDocumentModelBinding 511 + "', result is not a DocumentModel: " + value); 512 } else { 513 setSearchDocumentModel((DocumentModel) value); 514 } 515 } 516 if (searchDocumentModel == null) { 517 // generate a bare document model of given type 518 String docType = getSearchDocumentModelType(); 519 if (docType != null) { 520 DocumentModel bareDoc = DocumentModelFactory.createDocumentModel(docType); 521 setSearchDocumentModel(bareDoc); 522 } 523 } 524 } 525 return searchDocumentModel; 526 } 527 528 @Override 529 public void setSearchDocumentModel(DocumentModel searchDocumentModel) { 530 this.searchDocumentModel = searchDocumentModel; 531 if (pageProvider != null) { 532 pageProvider.setSearchDocumentModel(searchDocumentModel); 533 } 534 } 535 536 @Override 537 public void resetSearchDocumentModel() { 538 searchDocumentModel = null; 539 if (pageProvider != null) { 540 pageProvider.setSearchDocumentModel(null); 541 } 542 } 543 544 @Override 545 public String getSearchDocumentModelType() { 546 return searchDocumentModelType; 547 } 548 549 @Override 550 public List<String> getFlags() { 551 return flags; 552 } 553 554 @Override 555 public List<String> getResultLayoutColumns() { 556 return getCurrentResultLayoutColumns(); 557 } 558 559 @Override 560 @SuppressWarnings({ "unchecked", "rawtypes" }) 561 public List<String> getCurrentResultLayoutColumns() { 562 // always resolve binding if it is set 563 if (!StringUtils.isBlank(resultColumnsBinding)) { 564 Object res = resolveWithSearchDocument(new Function<FacesContext, Object>() { 565 @Override 566 public Object apply(FacesContext ctx) { 567 Object value = ComponentTagUtils.resolveElExpression(ctx, resultColumnsBinding); 568 if (value != null && !(value instanceof List)) { 569 log.error("Error processing expression '" + resultColumnsBinding + "', result is not a List: " 570 + value); 571 } 572 return value; 573 } 574 }); 575 if (res != null && res instanceof List) { 576 return ((List) res).isEmpty() ? null : (List) res; 577 } 578 } 579 return currentResultLayoutColumns; 580 } 581 582 @Override 583 public void setCurrentResultLayoutColumns(final List<String> resultColumns) { 584 if (isBlank(resultColumnsBinding) || !ComponentTagUtils.isStrictValueReference(resultColumnsBinding)) { 585 // set local values 586 currentResultLayoutColumns = resultColumns; 587 } else { 588 resolveWithSearchDocument(new Function<FacesContext, Object>() { 589 @Override 590 public Object apply(FacesContext ctx) { 591 ComponentTagUtils.applyValueExpression(ctx, resultColumnsBinding, resultColumns); 592 return null; 593 } 594 }); 595 } 596 } 597 598 @Override 599 public boolean hasResultLayoutColumnsBinding() { 600 return !isBlank(resultColumnsBinding); 601 } 602 603 @SuppressWarnings({ "unchecked", "rawtypes" }) 604 protected List<SortInfo> resolveSortInfos() { 605 if (sortInfosBinding == null) { 606 return null; 607 } 608 FacesContext context = FacesContext.getCurrentInstance(); 609 Object previousSearchDocValue = addSearchDocumentToELContext(context); 610 try { 611 Object value = ComponentTagUtils.resolveElExpression(context, sortInfosBinding); 612 if (value != null && !(value instanceof List)) { 613 log.error("Error processing expression '" + sortInfosBinding + "', result is not a List: '" + value 614 + "'"); 615 } 616 if (value == null) { 617 return null; 618 } 619 List<SortInfo> res = new ArrayList<SortInfo>(); 620 List listValue = (List) value; 621 for (Object listItem : listValue) { 622 if (listItem instanceof SortInfo) { 623 res.add((SortInfo) listItem); 624 } else if (listItem instanceof Map) { 625 // XXX: MapProperty does not implement containsKey, so 626 // resolve 627 // value instead 628 if (listItem instanceof MapProperty) { 629 try { 630 listItem = ((MapProperty) listItem).getValue(); 631 } catch (ClassCastException | PropertyException e) { 632 log.error("Cannot resolve sort info item: " + listItem, e); 633 } 634 } 635 Map map = (Map) listItem; 636 SortInfo sortInfo = SortInfo.asSortInfo(map); 637 if (sortInfo != null) { 638 res.add(sortInfo); 639 } else { 640 log.error("Cannot resolve sort info item: " + listItem); 641 } 642 } else { 643 log.error("Cannot resolve sort info item: " + listItem); 644 } 645 } 646 if (res.isEmpty()) { 647 return null; 648 } 649 return res; 650 } finally { 651 removeSearchDocumentFromELContext(context, previousSearchDocValue); 652 } 653 } 654 655 protected Long resolvePageSize() { 656 if (pageSizeBinding == null) { 657 return null; 658 } 659 FacesContext context = FacesContext.getCurrentInstance(); 660 Object previousSearchDocValue = addSearchDocumentToELContext(context); 661 try { 662 Object value = ComponentTagUtils.resolveElExpression(context, pageSizeBinding); 663 if (value == null) { 664 return null; 665 } 666 if (value instanceof String) { 667 try { 668 return Long.valueOf((String) value); 669 } catch (NumberFormatException e) { 670 log.error("Error processing expression '" + pageSizeBinding + "', result is not a Long: '" + value 671 + "'"); 672 } 673 } else if (value instanceof Number) { 674 return Long.valueOf(((Number) value).longValue()); 675 } 676 return null; 677 } finally { 678 removeSearchDocumentFromELContext(context, previousSearchDocValue); 679 } 680 } 681 682 protected Object addSearchDocumentToELContext(FacesContext facesContext) { 683 ExternalContext econtext = null; 684 if (facesContext != null) { 685 econtext = facesContext.getExternalContext(); 686 } 687 if (facesContext == null || econtext == null) { 688 log.error("JSF context is null: cannot expose variable '" + SEARCH_DOCUMENT_EL_VARIABLE 689 + "' for content view '" + getName() + "'"); 690 return null; 691 } 692 Map<String, Object> requestMap = econtext.getRequestMap(); 693 Object previousValue = requestMap.get(SEARCH_DOCUMENT_EL_VARIABLE); 694 requestMap.put(SEARCH_DOCUMENT_EL_VARIABLE, searchDocumentModel); 695 return previousValue; 696 } 697 698 protected void removeSearchDocumentFromELContext(FacesContext facesContext, Object previousValue) { 699 if (facesContext == null) { 700 // ignore 701 return; 702 } 703 ExternalContext econtext = facesContext.getExternalContext(); 704 if (econtext != null) { 705 Map<String, Object> requestMap = econtext.getRequestMap(); 706 requestMap.remove(SEARCH_DOCUMENT_EL_VARIABLE); 707 if (previousValue != null) { 708 requestMap.put(SEARCH_DOCUMENT_EL_VARIABLE, previousValue); 709 } 710 } else { 711 log.error("External context is null: cannot dispose variable '" + SEARCH_DOCUMENT_EL_VARIABLE 712 + "' for content view '" + getName() + "'"); 713 } 714 } 715 716 @Override 717 public boolean getShowPageSizeSelector() { 718 return showPageSizeSelector; 719 } 720 721 @Override 722 public boolean getShowRefreshCommand() { 723 return showRefreshCommand; 724 } 725 726 @Override 727 public boolean getShowFilterForm() { 728 return showFilterForm; 729 } 730 731 @Override 732 public boolean getShowTitle() { 733 return showTitle; 734 } 735 736 @Override 737 public String getEmptySentence() { 738 return emptySentence; 739 } 740 741 @Override 742 public boolean getTranslateEmptySentence() { 743 return translateEmptySentence; 744 } 745 746 @Override 747 public String toString() { 748 final StringBuilder buf = new StringBuilder(); 749 buf.append("ContentViewImpl") 750 .append(" {") 751 .append(" name=") 752 .append(name) 753 .append(", title=") 754 .append(title) 755 .append(", translateTitle=") 756 .append(translateTitle) 757 .append(", iconPath=") 758 .append(iconPath) 759 .append(", selectionList=") 760 .append(selectionList) 761 .append(", pagination=") 762 .append(pagination) 763 .append(", actionCategories=") 764 .append(actionCategories) 765 .append(", searchLayout=") 766 .append(searchLayout) 767 .append(", resultLayouts=") 768 .append(resultLayouts) 769 .append(", currentResultLayout=") 770 .append(currentResultLayout) 771 .append(", flags=") 772 .append(flags) 773 .append(", cacheKey=") 774 .append(cacheKey) 775 .append(", cacheSize=") 776 .append(cacheSize) 777 .append(", currentPageSize=") 778 .append(currentPageSize) 779 .append(", refreshEventNames=") 780 .append(refreshEventNames) 781 .append(", resetEventNames=") 782 .append(resetEventNames) 783 .append(", useGlobalPageSize=") 784 .append(useGlobalPageSize) 785 .append(", searchDocumentModel=") 786 .append(searchDocumentModel) 787 .append('}'); 788 return buf.toString(); 789 } 790 791 /* 792 * ----- PageProviderChangedListener ----- 793 */ 794 795 protected void raiseEvent(String eventName, Object... params) { 796 if (Events.exists()) { 797 Events.instance().raiseEvent(eventName, params); 798 } 799 } 800 801 protected void raiseEvent(String eventName) { 802 raiseEvent(eventName, name); 803 } 804 805 @Override 806 public void pageChanged(PageProvider<?> pageProvider) { 807 raiseEvent(CONTENT_VIEW_PAGE_CHANGED_EVENT); 808 } 809 810 @Override 811 public void refreshed(PageProvider<?> pageProvider) { 812 raiseEvent(CONTENT_VIEW_REFRESH_EVENT); 813 } 814 815 @SuppressWarnings("rawtypes") 816 @Override 817 public void resetPageProviderAggregates() { 818 if (pageProvider != null && pageProvider.hasAggregateSupport()) { 819 Map<String, ? extends Aggregate> aggs = pageProvider.getAggregates(); 820 for (Aggregate agg : aggs.values()) { 821 agg.resetSelection(); 822 } 823 } 824 } 825 826 @Override 827 public String getWaitForExecutionSentence() { 828 return waitForExecutionSentence; 829 } 830 831 /** 832 * @since 7.4 833 */ 834 public void setWaitForExecutionSentence(String waitForExecutionSentence) { 835 this.waitForExecutionSentence = waitForExecutionSentence; 836 } 837 838 @Override 839 public boolean isWaitForExecution() { 840 return waitForExecution; 841 } 842 843 /** 844 * @since 7.4 845 */ 846 public void setWaitForExecution(boolean waitForExecution) { 847 this.waitForExecution = waitForExecution; 848 } 849 850 @Override 851 public boolean isExecuted() { 852 return executed; 853 } 854 855 @Override 856 public void setExecuted(boolean executed) { 857 this.executed = executed; 858 } 859 860}