Java tutorial
/* * Copyright (c) 2002-2013, Mairie de Paris * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice * and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice * and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * License 1.0 */ package fr.paris.lutece.util.datatable; import fr.paris.lutece.portal.service.util.AppLogService; import fr.paris.lutece.portal.web.constants.Parameters; import fr.paris.lutece.portal.web.util.LocalizedDelegatePaginator; import fr.paris.lutece.portal.web.util.LocalizedPaginator; import fr.paris.lutece.util.ReferenceList; import fr.paris.lutece.util.UniqueIDGenerator; import fr.paris.lutece.util.html.IPaginator; import fr.paris.lutece.util.html.Paginator; import fr.paris.lutece.util.sort.AttributeComparator; import fr.paris.lutece.util.url.UrlItem; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.lang.StringUtils; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; /** * Class to manage data tables with freemarker macros * @param <T> Type of data to display */ public class DataTableManager<T> implements Serializable { /** * Serial version UID */ private static final long serialVersionUID = -3906455886374172029L; private static final String CONSTANT_GET = "get"; private static final String CONSTANT_IS = "is"; private static final String CONSTANT_DATA_TABLE_MANAGER_ID_PREFIX = "dataTableManager"; private String _strSortUrl; private List<DataTableColumn> _listColumn = new ArrayList<DataTableColumn>(); private FilterPanel _filterPanel; private IPaginator<T> _paginator; private String _strCurrentPageIndex = StringUtils.EMPTY; private int _nItemsPerPage; private int _nDefautlItemsPerPage; private boolean _bEnablePaginator; private Locale _locale; private String _strSortedAttributeName; private boolean _bIsAscSort; private String _strUid; /** * Private constructor */ protected DataTableManager() { generateDataTableId(); } /** * Constructor of the DataTableManager class * @param strSortUrl URL used by the paginator and to sort data * @param strFilterUrl URL used to filter data * @param nDefautlItemsPerPage Default number of items to display per page * @param bEnablePaginator True to enable pagination, false to disable it */ public DataTableManager(String strSortUrl, String strFilterUrl, int nDefautlItemsPerPage, boolean bEnablePaginator) { _filterPanel = new FilterPanel(strFilterUrl); _nDefautlItemsPerPage = nDefautlItemsPerPage; _nItemsPerPage = _nDefautlItemsPerPage; _strCurrentPageIndex = "1"; _bEnablePaginator = bEnablePaginator; generateDataTableId(); setSortUrl(strSortUrl); } /** * Add a column to this DataTableManager * @param strColumnTitle I18n key of the title of the column * @param strObjectName Name of the property of objects that should be * displayed in this column.<br /> * For example, if a class "Data" contains a property named * "title", then the value of the parameter <i>strObjectName</i> * should be "title". * @param bSortable True if the column is sortable, false otherwise */ public void addColumn(String strColumnTitle, String strObjectName, boolean bSortable) { _listColumn.add(new DataTableColumn(strColumnTitle, strObjectName, bSortable, DataTableColumnType.STRING)); } /** * Add a label column to this DataTableManager. Values of cells of this * column will be interpreted as i18n keys. * @param strColumnTitle I18n key of the title of the column * @param strObjectName Name of the property of objects that should be * displayed in this column. This properties must be i18n keys.<br /> * For example, if a class "Data" contains a property named * "title", then the value of the parameter <i>strObjectName</i> * should be "title". * @param bSortable True if the column is sortable, false otherwise */ public void addLabelColumn(String strColumnTitle, String strObjectName, boolean bSortable) { _listColumn.add(new DataTableColumn(strColumnTitle, strObjectName, bSortable, DataTableColumnType.LABEL)); } /** * Add an column to this DataTableManager that will display actions on * items. Actions are usually parameterized links. A DataTableManager can * only have 1 action column. The content of the action * column must be generated by a macro.this macro must have one parameter * named "item", and its name must be given to the macro <i>@tableData</i>. * @param strColumnTitle I18n key of the title of the column */ public void addActionColumn(String strColumnTitle) { _listColumn.add(new DataTableColumn(strColumnTitle, null, false, DataTableColumnType.ACTION)); } /** * Add a column to this DataTableManager * @param strColumnTitle I18n key of the title of the column * @param strObjectName Name of the property of objects that should be * displayed in this column.<br /> * For example, if a class "Data" contains a property named * "title", then the value of the parameter <i>strObjectName</i> * should be "title". * @param strLabelTrue I18n key of the label to display when the value is * true * @param strLabelFalse I18n key of the label to display when the value is * false */ public void addBooleanColumn(String strColumnTitle, String strObjectName, String strLabelTrue, String strLabelFalse) { _listColumn.add(new DataTableColumn(strColumnTitle, strObjectName, false, DataTableColumnType.BOOLEAN, strLabelTrue, strLabelFalse)); } /** * Add a free column to this DataTableManager. The content of this column * must be generated by a macro. The macro must have one parameter named * "item". * @param strColumnTitle I18n key of the title of the column * @param strFreemarkerMacroName Name of the freemarker macro that will * display the content of the column.<br /> * The macro must have a single parameter named <i>item</i> of * type T that will contain the object associated with a row of * the table. */ public void addFreeColumn(String strColumnTitle, String strFreemarkerMacroName) { _listColumn.add( new DataTableColumn(strColumnTitle, strFreemarkerMacroName, false, DataTableColumnType.ACTION)); } /** * Add an email column to this DataTableManager. Displayed cell will be a * "mailto:" link. * @param strColumnTitle I18n key of the title of the column * @param strObjectName Name of the property of objects that should be * displayed in this column.<br /> * For example, if a class "Data" contains a property named * "title", then the value of the parameter <i>strObjectName</i> * should be "title". * @param bSortable True if the column is sortable, false otherwise */ public void addEmailColumn(String strColumnTitle, String strObjectName, boolean bSortable) { _listColumn.add(new DataTableColumn(strColumnTitle, strObjectName, bSortable, DataTableColumnType.EMAIL)); } /** * Add a filter to the filter panel of this DataTableManager * @param filterType data type of the filter. For drop down list, use * {@link DataTableManager#addDropDownListFilter(String, String, ReferenceList) * addDropDownListFilter} instead * @param strParameterName Name of the parameter of the object to filter.<br/> * For example, if this filter should be applied on the parameter * "title" of a class named "Data", then the value of the * parameter <i>strParameterName</i> should be "title". * @param strFilterLabel Label describing the filter */ public void addFilter(DataTableFilterType filterType, String strParameterName, String strFilterLabel) { _filterPanel.addFilter(filterType, strParameterName, strFilterLabel); } /** * Add a drop down list filter to the filter panel of this DataTableManager * @param strParameterName Name of the parameter of the object to filter.<br/> * For example, if this filter should be applied on the parameter * "title" of a class named "Data", then the value of the * parameter <i>strParameterName</i> should be "title". * @param strFilterLabel Label describing the filter * @param refList Reference list containing data of the drop down list */ public void addDropDownListFilter(String strParameterName, String strFilterLabel, ReferenceList refList) { _filterPanel.addDropDownListFilter(strParameterName, strFilterLabel, refList); } /** * Apply filters on an objects list, sort it and update pagination values. * @param request The request * @param items Collection of objects to filter, sort and paginate */ public void filterSortAndPaginate(HttpServletRequest request, List<T> items) { List<T> filteredSortedPaginatedItems = new ArrayList<T>(items); boolean bSubmitedDataTable = hasDataTableFormBeenSubmited(request); // FILTER Collection<DataTableFilter> listFilters = _filterPanel.getListFilter(); boolean bUpdateFilter = false; boolean bResetFilter = false; // We check if filters must be updated or cleared if (bSubmitedDataTable) { bResetFilter = StringUtils.equals( request.getParameter(FilterPanel.PARAM_FILTER_PANEL_PREFIX + FilterPanel.PARAM_RESET_FILTERS), Boolean.TRUE.toString()); bUpdateFilter = true; if (!bResetFilter) { bUpdateFilter = StringUtils.equals( request.getParameter( FilterPanel.PARAM_FILTER_PANEL_PREFIX + FilterPanel.PARAM_UPDATE_FILTERS), Boolean.TRUE.toString()); } } for (DataTableFilter filter : listFilters) { String strFilterValue; if (bSubmitedDataTable && bUpdateFilter) { // We update or clear filters strFilterValue = request .getParameter(FilterPanel.PARAM_FILTER_PANEL_PREFIX + filter.getParameterName()); if (!bResetFilter && (filter.getFilterType() == DataTableFilterType.BOOLEAN) && (strFilterValue == null)) { strFilterValue = Boolean.FALSE.toString(); } filter.setValue(strFilterValue); } else { strFilterValue = filter.getValue(); } if (StringUtils.isNotBlank(strFilterValue)) { List<T> bufferList = new ArrayList<T>(); for (T item : filteredSortedPaginatedItems) { Method method = getMethod(item, filter.getParameterName(), CONSTANT_GET); if ((method == null) && (filter.getFilterType() == DataTableFilterType.BOOLEAN)) { method = getMethod(item, filter.getParameterName(), CONSTANT_IS); } if (method != null) { try { Object value = method.invoke(item); if ((value != null) && strFilterValue.equals(value.toString())) { bufferList.add(item); } } catch (Exception e) { AppLogService.error(e.getMessage(), e); } } } filteredSortedPaginatedItems.retainAll(bufferList); } } // SORT if (bSubmitedDataTable) { // We update the sort parameters String strSortedAttributeName = request.getParameter(Parameters.SORTED_ATTRIBUTE_NAME); if (strSortedAttributeName != null) { // We update sort properties _strSortedAttributeName = strSortedAttributeName; _bIsAscSort = Boolean.parseBoolean(request.getParameter(Parameters.SORTED_ASC)); } } // We sort the items if (_strSortedAttributeName != null) { Collections.sort(filteredSortedPaginatedItems, new AttributeComparator(_strSortedAttributeName, _bIsAscSort)); } // PAGINATION if (bSubmitedDataTable) { // We update the pagination properties if (_bEnablePaginator) { int nOldItemsPerPage = _nItemsPerPage; _nItemsPerPage = Paginator.getItemsPerPage(request, Paginator.PARAMETER_ITEMS_PER_PAGE, _nItemsPerPage, _nDefautlItemsPerPage); // If the number of items per page has changed, we switch to the first page if (_nItemsPerPage != nOldItemsPerPage) { _strCurrentPageIndex = Integer.toString(1); } else { _strCurrentPageIndex = Paginator.getPageIndex(request, Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex); } } else { _strCurrentPageIndex = Integer.toString(1); _nItemsPerPage = filteredSortedPaginatedItems.size(); } } // We paginate create the new paginator _paginator = new LocalizedPaginator<T>(filteredSortedPaginatedItems, _nItemsPerPage, getSortUrl(), Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex, request.getLocale()); } /** * Get the filter panel of the DataTableManager * @return The filter panel of the DataTableManager */ public FilterPanel getFilterPanel() { return _filterPanel; } /** * Set the filter panel of the DataTableManager * @param filterPanel Filter panel */ public void setFilterPanel(FilterPanel filterPanel) { _filterPanel = filterPanel; } /** * Get the list of columns of this DataTableManager * @return The list of columns of this DataTableManager */ public List<DataTableColumn> getListColumn() { return _listColumn; } /** * Set the list of columns of this DataTableManager * @param listColumn The list of columns of this DataTableManager */ public void setListColumn(List<DataTableColumn> listColumn) { _listColumn = listColumn; } /** * Get the sort url of this DataTableManager * @return The sort url of this DataTableManager */ public String getSortUrl() { return _strSortUrl; } /** * Set the sort url of this DataTableManager * @param strSortUrl The sort url of this DataTableManager */ public void setSortUrl(String strSortUrl) { _strSortUrl = strSortUrl; if ((_strSortUrl != null) && StringUtils.isNotEmpty(_strSortUrl) && !StringUtils.contains(_strSortUrl, getId())) { // We add to the sort URL the unique parameter of this data table manager UrlItem urlItem = new UrlItem(_strSortUrl); urlItem.addParameter(getId(), getId()); _strSortUrl = urlItem.getUrl(); } } /** * Get the filtered, sorted and paginated items collection of this * DataTableManager * @return The filtered, sorted and paginated items collection of this * DataTableManager */ public List<T> getItems() { return _paginator.getPageItems(); } /** * Set the items to display. The list of items must be fintered, sorted and * paginated. Methods * {@link DataTableManager#getAndUpdatePaginator(HttpServletRequest ) * getAndUpdatePaginator}, * {@link DataTableManager#getAndUpdateSort(HttpServletRequest ) * getAndUpdateSort} and * {@link DataTableManager#getAndUpdateFilter(HttpServletRequest, Object) * getAndUpdateFilter} must have been * called before the generation of the list of items. * @param items The filtered sorted and paginated list of items to display * @param nTotalItemsNumber The total number of items */ public void setItems(List<T> items, int nTotalItemsNumber) { _paginator = new LocalizedDelegatePaginator<T>(items, _nItemsPerPage, getSortUrl(), Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex, nTotalItemsNumber, _locale); } /** * Clear the items stored by this DataTableManager so that the garbage * collector can free the memory they use. */ public void clearItems() { _paginator = null; _locale = null; } /** * Internal method. Get the paginator.<br/> * Do not use this method, use * {@link DataTableManager#getAndUpdatePaginator(HttpServletRequest ) * getAndUpdatePaginator} instead to get up to date values ! * @return The paginator */ public IPaginator<T> getPaginator() { return _paginator; } /** * Get the enable paginator boolean * @return True if pagination is active, false otherwise */ public boolean getEnablePaginator() { return _bEnablePaginator; } /** * Get the locale * @return The locale */ public Locale getLocale() { return _locale; } /** * Set the locale * @param locale The locale */ public void setLocale(Locale locale) { _locale = locale; } /** * Get the unique id of this data table manager * @return The unique id of this data table manager */ public String getId() { return _strUid; } /** * Get the paginator updated with values in the request * @param request The request * @return The paginator up to date */ public DataTablePaginationProperties getAndUpdatePaginator(HttpServletRequest request) { DataTablePaginationProperties paginationProperties = null; if (_bEnablePaginator) { paginationProperties = new DataTablePaginationProperties(); if (hasDataTableFormBeenSubmited(request)) { _strCurrentPageIndex = Paginator.getPageIndex(request, Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex); _nItemsPerPage = Paginator.getItemsPerPage(request, Paginator.PARAMETER_ITEMS_PER_PAGE, _nItemsPerPage, _nDefautlItemsPerPage); } paginationProperties.setItemsPerPage(_nItemsPerPage); int nCurrentPageIndex = 1; if (!StringUtils.isEmpty(_strCurrentPageIndex)) { nCurrentPageIndex = Integer.parseInt(_strCurrentPageIndex); } paginationProperties.setCurrentPageIndex(nCurrentPageIndex); } _locale = (request != null) ? request.getLocale() : Locale.getDefault(); return paginationProperties; } /** * Get sort properties updated with values in the request * @param request The request * @return The sort properties up to date */ public DataTableSort getAndUpdateSort(HttpServletRequest request) { if (hasDataTableFormBeenSubmited(request)) { String strSortedAttributeName = request.getParameter(Parameters.SORTED_ATTRIBUTE_NAME); if (strSortedAttributeName != null) { // We update sort properties _strSortedAttributeName = strSortedAttributeName; _bIsAscSort = Boolean.parseBoolean(request.getParameter(Parameters.SORTED_ASC)); } } DataTableSort sort = new DataTableSort(_strSortedAttributeName, _bIsAscSort); return sort; } /** * Get filter properties updated with values in the request * @param request The request * @param <K> Type of the filter to use. This type must have accessors for * every declared filter. * @param filterObject Filter to apply. * @return The filter properties up to date */ public <K> K getAndUpdateFilter(HttpServletRequest request, K filterObject) { List<DataTableFilter> listFilters = _filterPanel.getListFilter(); boolean bSubmitedDataTable = hasDataTableFormBeenSubmited(request); boolean bResetFilter = false; boolean bUpdateFilter = false; Map<String, Object> mapFilter = new HashMap<String, Object>(); if (bSubmitedDataTable) { bUpdateFilter = true; StringUtils.equals( request.getParameter(FilterPanel.PARAM_FILTER_PANEL_PREFIX + FilterPanel.PARAM_RESET_FILTERS), Boolean.TRUE.toString()); if (!bResetFilter) { bUpdateFilter = StringUtils.equals( request.getParameter( FilterPanel.PARAM_FILTER_PANEL_PREFIX + FilterPanel.PARAM_UPDATE_FILTERS), Boolean.TRUE.toString()); } } for (DataTableFilter filter : listFilters) { if (bSubmitedDataTable) { String strFilterValue = request .getParameter(FilterPanel.PARAM_FILTER_PANEL_PREFIX + filter.getParameterName()); if (bUpdateFilter) { filter.setValue(strFilterValue); } } if (StringUtils.isNotBlank(filter.getValue())) { mapFilter.put(filter.getParameterName(), filter.getValue()); } } try { BeanUtilsBean.getInstance().populate(filterObject, mapFilter); } catch (IllegalAccessException e) { AppLogService.error(e.getMessage(), e); return null; } catch (InvocationTargetException e) { AppLogService.error(e.getMessage(), e); return null; } return filterObject; } /** * Internal method. Get the prefix of html attributes used by filters * @return The prefix of html attributes used by filters */ public String getFilterPanelPrefix() { return FilterPanel.PARAM_FILTER_PANEL_PREFIX; } /** * Return the getter method of the object obj for the attribute * <i>strAttributName</i> * @param obj the object * @param strAttributName The name of the attribute to get the getter * @param strMethodPrefix Prefix of the name of the method * @return method Method of the object obj for the attribute * <i>strAttributName</i> */ private Method getMethod(Object obj, String strAttributName, String strMethodPrefix) { Method method = null; String strFirstLetter = strAttributName.substring(0, 1).toUpperCase(); String strMethodName = strMethodPrefix + strFirstLetter + strAttributName.substring(1, strAttributName.length()); try { method = obj.getClass().getMethod(strMethodName); } catch (Exception e) { AppLogService.debug(e); } return method; } /** * Generates the unique identifier of this data table manager */ private void generateDataTableId() { this._strUid = CONSTANT_DATA_TABLE_MANAGER_ID_PREFIX + UniqueIDGenerator.getNewId(); } /** * Check if a request contain data of this data table manager * @param request The request * @return True if a form of this data table manager has been submited, * false otherwise */ private boolean hasDataTableFormBeenSubmited(HttpServletRequest request) { return (request != null) ? StringUtils.equals(request.getParameter(getId()), getId()) : false; } }