/** * Licensed under the Artistic License; you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://displaytag.sourceforge.net/license.html * * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ package org.displaytag.properties; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.UnhandledException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.displaytag.Messages; import org.displaytag.decorator.DecoratorFactory; import org.displaytag.decorator.DefaultDecoratorFactory; import org.displaytag.exception.FactoryInstantiationException; import org.displaytag.exception.TablePropertiesLoadException; import org.displaytag.localization.I18nResourceProvider; import org.displaytag.localization.LocaleResolver; import org.displaytag.util.DefaultRequestHelperFactory; import org.displaytag.util.ReflectHelper; import org.displaytag.util.RequestHelperFactory; /** * The properties used by the Table tags. The properties are loaded in the following order, in increasing order of * priority. The locale of getInstance() is used to determine the locale of the property file to use; if the key * required does not exist in the specified file, the key will be loaded from a more general property file. * <ol> * <li>First, from the TableTag.properties included with the DisplayTag distribution.</li> * <li>Then, from the file displaytag.properties, if it is present; these properties are intended to be set by the user * for sitewide application. Messages are gathered according to the Locale of the property file.</li> * <li>Finally, if this class has a userProperties defined, all of the properties from that Properties object are * copied in as well.</li> * </ol> * @author Fabrizio Giustina * @author rapruitt * @version $Revision: 987 $ ($Author: fgiust $) */ public final class TableProperties implements Cloneable { /** * name of the default properties file name ("displaytag.properties"). */ public static final String DEFAULT_FILENAME = "displaytag.properties"; //$NON-NLS-1$ /** * The name of the local properties file that is searched for on the classpath. Settings in this file will override * the defaults loaded from TableTag.properties. */ public static final String LOCAL_PROPERTIES = "displaytag"; //$NON-NLS-1$ /** * property <code>export.banner</code>. */ public static final String PROPERTY_STRING_EXPORTBANNER = "export.banner"; //$NON-NLS-1$ /** * property <code>export.banner.sepchar</code>. */ public static final String PROPERTY_STRING_EXPORTBANNER_SEPARATOR = "export.banner.sepchar"; //$NON-NLS-1$ /** * property <code>export.decorated</code>. */ public static final String PROPERTY_BOOLEAN_EXPORTDECORATED = "export.decorated"; //$NON-NLS-1$ /** * property <code>export.amount</code>. */ public static final String PROPERTY_STRING_EXPORTAMOUNT = "export.amount"; //$NON-NLS-1$ /** * property <code>sort.amount</code>. */ public static final String PROPERTY_STRING_SORTAMOUNT = "sort.amount"; //$NON-NLS-1$ /** * property <code>basic.show.header</code>. */ public static final String PROPERTY_BOOLEAN_SHOWHEADER = "basic.show.header"; //$NON-NLS-1$ /** * property <code>basic.msg.empty_list</code>. */ public static final String PROPERTY_STRING_EMPTYLIST_MESSAGE = "basic.msg.empty_list"; //$NON-NLS-1$ /** * property <code>basic.msg.empty_list_row</code>. */ public static final String PROPERTY_STRING_EMPTYLISTROW_MESSAGE = "basic.msg.empty_list_row"; //$NON-NLS-1$ /** * property <code>basic.empty.showtable</code>. */ public static final String PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE = "basic.empty.showtable"; //$NON-NLS-1$ /** * property <code>paging.banner.placement</code>. */ public static final String PROPERTY_STRING_BANNER_PLACEMENT = "paging.banner.placement"; //$NON-NLS-1$ /** * property <code>error.msg.invalid_page</code>. */ public static final String PROPERTY_STRING_PAGING_INVALIDPAGE = "error.msg.invalid_page"; //$NON-NLS-1$ /** * property <code>paging.banner.item_name</code>. */ public static final String PROPERTY_STRING_PAGING_ITEM_NAME = "paging.banner.item_name"; //$NON-NLS-1$ /** * property <code>paging.banner.items_name</code>. */ public static final String PROPERTY_STRING_PAGING_ITEMS_NAME = "paging.banner.items_name"; //$NON-NLS-1$ /** * property <code>paging.banner.no_items_found</code>. */ public static final String PROPERTY_STRING_PAGING_NOITEMS = "paging.banner.no_items_found"; //$NON-NLS-1$ /** * property <code>paging.banner.one_item_found</code>. */ public static final String PROPERTY_STRING_PAGING_FOUND_ONEITEM = "paging.banner.one_item_found"; //$NON-NLS-1$ /** * property <code>paging.banner.all_items_found</code>. */ public static final String PROPERTY_STRING_PAGING_FOUND_ALLITEMS = "paging.banner.all_items_found"; //$NON-NLS-1$ /** * property <code>paging.banner.some_items_found</code>. */ public static final String PROPERTY_STRING_PAGING_FOUND_SOMEITEMS = "paging.banner.some_items_found"; //$NON-NLS-1$ /** * property <code>paging.banner.group_size</code>. */ public static final String PROPERTY_INT_PAGING_GROUPSIZE = "paging.banner.group_size"; //$NON-NLS-1$ /** * property <code>paging.banner.onepage</code>. */ public static final String PROPERTY_STRING_PAGING_BANNER_ONEPAGE = "paging.banner.onepage"; //$NON-NLS-1$ /** * property <code>paging.banner.first</code>. */ public static final String PROPERTY_STRING_PAGING_BANNER_FIRST = "paging.banner.first"; //$NON-NLS-1$ /** * property <code>paging.banner.last</code>. */ public static final String PROPERTY_STRING_PAGING_BANNER_LAST = "paging.banner.last"; //$NON-NLS-1$ /** * property <code>paging.banner.full</code>. */ public static final String PROPERTY_STRING_PAGING_BANNER_FULL = "paging.banner.full"; //$NON-NLS-1$ /** * property <code>paging.banner.page.link</code>. */ public static final String PROPERTY_STRING_PAGING_PAGE_LINK = "paging.banner.page.link"; //$NON-NLS-1$ /** * property <code>paging.banner.page.selected</code>. */ public static final String PROPERTY_STRING_PAGING_PAGE_SELECTED = "paging.banner.page.selected"; //$NON-NLS-1$ /** * property <code>paging.banner.page.separator</code>. */ public static final String PROPERTY_STRING_PAGING_PAGE_SPARATOR = "paging.banner.page.separator"; //$NON-NLS-1$ /** * property <code>factory.requestHelper</code>. */ public static final String PROPERTY_CLASS_REQUESTHELPERFACTORY = "factory.requestHelper"; //$NON-NLS-1$ /** * property <code>factory.decorators</code>. */ public static final String PROPERTY_CLASS_DECORATORFACTORY = "factory.decorator"; //$NON-NLS-1$ /** * property <code>locale.provider</code>. */ public static final String PROPERTY_CLASS_LOCALEPROVIDER = "locale.provider"; //$NON-NLS-1$ /** * property <code>locale.resolver</code>. */ public static final String PROPERTY_CLASS_LOCALERESOLVER = "locale.resolver"; //$NON-NLS-1$ /** * property <code>css.tr.even</code>: holds the name of the css class for even rows. Defaults to * <code>even</code>. */ public static final String PROPERTY_CSS_TR_EVEN = "css.tr.even"; //$NON-NLS-1$ /** * property <code>css.tr.odd</code>: holds the name of the css class for odd rows. Defaults to <code>odd</code>. */ public static final String PROPERTY_CSS_TR_ODD = "css.tr.odd"; //$NON-NLS-1$ /** * property <code>css.table</code>: holds the name of the css class added to the main table tag. By default no * css class is added. */ public static final String PROPERTY_CSS_TABLE = "css.table"; //$NON-NLS-1$ /** * property <code>css.th.sortable</code>: holds the name of the css class added to the the header of a sortable * column. By default no css class is added. */ public static final String PROPERTY_CSS_TH_SORTABLE = "css.th.sortable"; //$NON-NLS-1$ /** * property <code>css.th.sorted</code>: holds the name of the css class added to the the header of a sorted * column. Defaults to <code>sorted</code>. */ public static final String PROPERTY_CSS_TH_SORTED = "css.th.sorted"; //$NON-NLS-1$ /** * property <code>css.th.ascending</code>: holds the name of the css class added to the the header of a column * sorted in ascending order. Defaults to <code>order1</code>. */ public static final String PROPERTY_CSS_TH_SORTED_ASCENDING = "css.th.ascending"; //$NON-NLS-1$ /** * property <code>css.th.descending</code>: holds the name of the css class added to the the header of a column * sorted in descending order. Defaults to <code>order2</code>. */ public static final String PROPERTY_CSS_TH_SORTED_DESCENDING = "css.th.descending"; //$NON-NLS-1$ /** * prefix used for all the properties related to export ("export"). The full property name is <code>export.</code> * <em>[export type]</em><code>.</code><em>[property name]</em> */ public static final String PROPERTY_EXPORT_PREFIX = "export"; //$NON-NLS-1$ /** * suffix used to set the export decorator property name. The full property name is <code>export.</code> * <em>[export type]</em><code>.</code><em>decorator</em> */ public static final String PROPERTY_EXPORT_DECORATOR_SUFFIX = "decorator"; //$NON-NLS-1$ /** * property <code>export.types</code>: holds the list of export available export types. */ public static final String PROPERTY_EXPORTTYPES = "export.types"; //$NON-NLS-1$ /** * export property <code>label</code>. */ public static final String EXPORTPROPERTY_STRING_LABEL = "label"; //$NON-NLS-1$ /** * export property <code>class</code>. */ public static final String EXPORTPROPERTY_STRING_CLASS = "class"; //$NON-NLS-1$ /** * export property <code>include_header</code>. */ public static final String EXPORTPROPERTY_BOOLEAN_EXPORTHEADER = "include_header"; //$NON-NLS-1$ /** * export property <code>filename</code>. */ public static final String EXPORTPROPERTY_STRING_FILENAME = "filename"; //$NON-NLS-1$ /** * Property <code>pagination.sort.param</code>. If external pagination and sorting is used, it holds the name of * the parameter used to hold the sort criterion in generated links */ public static final String PROPERTY_STRING_PAGINATION_SORT_PARAM = "pagination.sort.param"; //$NON-NLS-1$ /** * Property <code>pagination.sortdirection.param</code>. If external pagination and sorting is used, it holds the * name of the parameter used to hold the sort direction in generated links (asc or desc) */ public static final String PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM = "pagination.sortdirection.param"; //$NON-NLS-1$ /** * Property <code>pagination.pagenumber.param</code>. If external pagination and sorting is used, it holds the * name of the parameter used to hold the page number in generated links */ public static final String PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM = "pagination.pagenumber.param"; //$NON-NLS-1$ /** * Property <code>pagination.searchid.param</code>. If external pagination and sorting is used, it holds the name * of the parameter used to hold the search ID in generated links */ public static final String PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM = "pagination.searchid.param"; //$NON-NLS-1$ /** * Property <code>pagination.sort.asc.value</code>. If external pagination and sorting is used, it holds the * value of the parameter of the sort direction parameter for "ascending" */ public static final String PROPERTY_STRING_PAGINATION_ASC_VALUE = "pagination.sort.asc.value"; //$NON-NLS-1$ /** * Property <code>pagination.sort.desc.value</code>. If external pagination and sorting is used, it holds the * value of the parameter of the sort direction parameter for "descending" */ public static final String PROPERTY_STRING_PAGINATION_DESC_VALUE = "pagination.sort.desc.value"; //$NON-NLS-1$ /** * Property <code>pagination.sort.skippagenumber</code>. If external pagination and sorting is used, it * determines if the current page number must be added in sort links or not. If this property is true, it means that * each click on a generated sort link will re-sort the list, and go back to the default page number. If it is * false, each click on a generated sort link will re-sort the list, and ask the current page number. */ public static final String PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT = "pagination.sort.skippagenumber"; //$NON-NLS-1$ // </JBN> /** * Separator char used in property names. */ private static final char SEP = '.'; /** * logger. */ private static Log log = LogFactory.getLog(TableProperties.class); /** * The userProperties are local, non-default properties; these settings override the defaults from * displaytag.properties and TableTag.properties. */ private static Properties userProperties = new Properties(); /** * Configured resource provider. If no ResourceProvider is configured, an no-op one is used. This instance is * initialized at first use and shared. */ private static I18nResourceProvider resourceProvider; /** * Configured locale resolver. */ private static LocaleResolver localeResolver; /** * TableProperties for each locale are loaded as needed, and cloned for public usage. */ private static Map prototypes = new HashMap(); /** * Loaded properties (defaults from defaultProperties + custom from bundle). */ private Properties properties; /** * The locale for these properties. */ private Locale locale; /** * Cache for dinamically instantiated object (request factory, decorator factory). */ private Map objectCache = new HashMap(); /** * Setter for I18nResourceProvider. A resource provider is usually set using displaytag properties, this accessor is * needed for tests. * @param provider I18nResourceProvider instance */ protected static void setResourceProvider(I18nResourceProvider provider) { resourceProvider = provider; } /** * Setter for LocaleResolver. A locale resolver is usually set using displaytag properties, this accessor is needed * for tests. * @param resolver LocaleResolver instance */ protected static void setLocaleResolver(LocaleResolver resolver) { localeResolver = resolver; } /** * Loads default properties (TableTag.properties). * @return loaded properties * @throws TablePropertiesLoadException if default properties file can't be found */ private static Properties loadBuiltInProperties() throws TablePropertiesLoadException { Properties defaultProperties = new Properties(); try { defaultProperties.load(TableProperties.class.getResourceAsStream(DEFAULT_FILENAME)); } catch (IOException e) { throw new TablePropertiesLoadException(TableProperties.class, DEFAULT_FILENAME, e); } return defaultProperties; } /** * Loads user properties (displaytag.properties) according to the given locale. User properties are not guarantee to * exist, so the method can return <code>null</code> (no exception will be thrown). * @param locale requested Locale * @return loaded properties */ private static ResourceBundle loadUserProperties(Locale locale) { ResourceBundle bundle = null; try { bundle = ResourceBundle.getBundle(LOCAL_PROPERTIES, locale); } catch (MissingResourceException e) { // if no resource bundle is found, try using the context classloader try { bundle = ResourceBundle.getBundle(LOCAL_PROPERTIES, locale, Thread .currentThread() .getContextClassLoader()); } catch (MissingResourceException mre) { if (log.isDebugEnabled()) { log.debug(Messages.getString("TableProperties.propertiesnotfound", //$NON-NLS-1$ new Object[]{mre.getMessage()})); } } } return bundle; } /** * Returns the configured Locale Resolver. This method is called before the loading of localized properties. * @return LocaleResolver instance. * @throws TablePropertiesLoadException if the default <code>TableTag.properties</code> file is not found. */ public static LocaleResolver getLocaleResolverInstance() throws TablePropertiesLoadException { if (localeResolver == null) { // special handling, table properties is not yet instantiated String className = null; ResourceBundle defaultUserProperties = loadUserProperties(Locale.getDefault()); // if available, user properties have higher precedence if (defaultUserProperties != null) { try { className = defaultUserProperties.getString(PROPERTY_CLASS_LOCALERESOLVER); } catch (MissingResourceException e) { // no problem } } // still null? load defaults if (className == null) { Properties defaults = loadBuiltInProperties(); className = defaults.getProperty(PROPERTY_CLASS_LOCALERESOLVER); } if (className != null) { try { Class classProperty = ReflectHelper.classForName(className); localeResolver = (LocaleResolver) classProperty.newInstance(); log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$ new Object[]{ClassUtils.getShortClassName(LocaleResolver.class), className})); } catch (Throwable e) { log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$ new Object[]{ ClassUtils.getShortClassName(LocaleResolver.class), e.getClass().getName(), e.getMessage()})); } } else { log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$ new Object[]{ClassUtils.getShortClassName(LocaleResolver.class)})); } // still null? if (localeResolver == null) { // fallback locale resolver localeResolver = new LocaleResolver() { public Locale resolveLocale(HttpServletRequest request) { return request.getLocale(); } }; } } return localeResolver; } /** * Initialize a new TableProperties loading the default properties file and the user defined one. There is no * caching used here, caching is assumed to occur in the getInstance factory method. * @param myLocale the locale we are in * @throws TablePropertiesLoadException for errors during loading of properties files */ private TableProperties(Locale myLocale) throws TablePropertiesLoadException { this.locale = myLocale; // default properties will not change unless this class is reloaded Properties defaultProperties = loadBuiltInProperties(); properties = new Properties(defaultProperties); addProperties(myLocale); // Now copy in the user properties (properties file set by calling setUserProperties()). // note setUserProperties() MUST BE CALLED before the first TableProperties instantation Enumeration keys = userProperties.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key != null) { properties.setProperty(key, (String) userProperties.get(key)); } } } /** * Try to load the properties from the local properties file, displaytag.properties, and merge them into the * existing properties. * @param userLocale the locale from which the properties are to be loaded */ private void addProperties(Locale userLocale) { ResourceBundle bundle = loadUserProperties(userLocale); if (bundle != null) { Enumeration keys = bundle.getKeys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); properties.setProperty(key, bundle.getString(key)); } } } /** * Clones the properties as well. * @return a new clone of oneself */ protected Object clone() { TableProperties twin; try { twin = (TableProperties) super.clone(); } catch (CloneNotSupportedException e) { // should never happen throw new UnhandledException(e); } twin.properties = (Properties) this.properties.clone(); return twin; } /** * Returns a new TableProperties instance for the given locale. * @param request HttpServletRequest needed to extract the locale to use. If null the default locale will be used. * @return TableProperties instance */ public static TableProperties getInstance(HttpServletRequest request) { Locale locale; if (request != null) { locale = getLocaleResolverInstance().resolveLocale(request); } else { // for some configuration parameters locale doesn't matter locale = Locale.getDefault(); } TableProperties props = (TableProperties) prototypes.get(locale); if (props == null) { TableProperties lprops = new TableProperties(locale); prototypes.put(locale, lprops); props = lprops; } return (TableProperties) props.clone(); } /** * Unload all cached properties. This will not clear properties set by by setUserProperties; you must clear those * manually. */ public static void clearProperties() { prototypes.clear(); } /** * Local, non-default properties; these settings override the defaults from displaytag.properties and * TableTag.properties. Please note that the values are copied in, so that multiple calls with non-overlapping * properties will be merged, not overwritten. Note: setUserProperties() MUST BE CALLED before the first * TableProperties instantation. * @param overrideProperties - The local, non-default properties */ public static void setUserProperties(Properties overrideProperties) { // copy keys here, so that this can be invoked more than once from different sources. // if default properties are not yet loaded they will be copied in constructor Enumeration keys = overrideProperties.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key != null) { userProperties.setProperty(key, (String) overrideProperties.get(key)); } } } /** * The locale for which these properties are intended. * @return the locale */ public Locale getLocale() { return locale; } /** * Getter for the <code>PROPERTY_STRING_PAGING_INVALIDPAGE</code> property. * @return String */ public String getPagingInvalidPage() { return getProperty(PROPERTY_STRING_PAGING_INVALIDPAGE); } /** * Getter for the <code>PROPERTY_STRING_PAGING_ITEM_NAME</code> property. * @return String */ public String getPagingItemName() { return getProperty(PROPERTY_STRING_PAGING_ITEM_NAME); } /** * Getter for the <code>PROPERTY_STRING_PAGING_ITEMS_NAME</code> property. * @return String */ public String getPagingItemsName() { return getProperty(PROPERTY_STRING_PAGING_ITEMS_NAME); } /** * Getter for the <code>PROPERTY_STRING_PAGING_NOITEMS</code> property. * @return String */ public String getPagingFoundNoItems() { return getProperty(PROPERTY_STRING_PAGING_NOITEMS); } /** * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ONEITEM</code> property. * @return String */ public String getPagingFoundOneItem() { return getProperty(PROPERTY_STRING_PAGING_FOUND_ONEITEM); } /** * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_ALLITEMS</code> property. * @return String */ public String getPagingFoundAllItems() { return getProperty(PROPERTY_STRING_PAGING_FOUND_ALLITEMS); } /** * Getter for the <code>PROPERTY_STRING_PAGING_FOUND_SOMEITEMS</code> property. * @return String */ public String getPagingFoundSomeItems() { return getProperty(PROPERTY_STRING_PAGING_FOUND_SOMEITEMS); } /** * Getter for the <code>PROPERTY_INT_PAGING_GROUPSIZE</code> property. * @return int */ public int getPagingGroupSize() { // default size is 8 return getIntProperty(PROPERTY_INT_PAGING_GROUPSIZE, 8); } /** * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_ONEPAGE</code> property. * @return String */ public String getPagingBannerOnePage() { return getProperty(PROPERTY_STRING_PAGING_BANNER_ONEPAGE); } /** * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FIRST</code> property. * @return String */ public String getPagingBannerFirst() { return getProperty(PROPERTY_STRING_PAGING_BANNER_FIRST); } /** * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_LAST</code> property. * @return String */ public String getPagingBannerLast() { return getProperty(PROPERTY_STRING_PAGING_BANNER_LAST); } /** * Getter for the <code>PROPERTY_STRING_PAGING_BANNER_FULL</code> property. * @return String */ public String getPagingBannerFull() { return getProperty(PROPERTY_STRING_PAGING_BANNER_FULL); } /** * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_LINK</code> property. * @return String */ public String getPagingPageLink() { return getProperty(PROPERTY_STRING_PAGING_PAGE_LINK); } /** * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SELECTED</code> property. * @return String */ public String getPagingPageSelected() { return getProperty(PROPERTY_STRING_PAGING_PAGE_SELECTED); } /** * Getter for the <code>PROPERTY_STRING_PAGING_PAGE_SPARATOR</code> property. * @return String */ public String getPagingPageSeparator() { return getProperty(PROPERTY_STRING_PAGING_PAGE_SPARATOR); } /** * Is the given export option enabled? * @param exportType instance of MediaTypeEnum * @return boolean true if export is enabled */ public boolean getAddExport(MediaTypeEnum exportType) { return getBooleanProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName()); } /** * Should headers be included in given export type? * @param exportType instance of MediaTypeEnum * @return boolean true if export should include headers */ public boolean getExportHeader(MediaTypeEnum exportType) { return getBooleanProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName() + SEP + EXPORTPROPERTY_BOOLEAN_EXPORTHEADER); } /** * Returns the label for the given export option. * @param exportType instance of MediaTypeEnum * @return String label */ public String getExportLabel(MediaTypeEnum exportType) { return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName() + SEP + EXPORTPROPERTY_STRING_LABEL); } /** * Returns the file name for the given media. Can be null * @param exportType instance of MediaTypeEnum * @return String filename */ public String getExportFileName(MediaTypeEnum exportType) { return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportType.getName() + SEP + EXPORTPROPERTY_STRING_FILENAME); } /** * Getter for the <code>PROPERTY_BOOLEAN_EXPORTDECORATED</code> property. * @return boolean <code>true</code> if decorators should be used in exporting */ public boolean getExportDecorated() { return getBooleanProperty(PROPERTY_BOOLEAN_EXPORTDECORATED); } /** * Getter for the <code>PROPERTY_STRING_EXPORTBANNER</code> property. * @return String */ public String getExportBanner() { return getProperty(PROPERTY_STRING_EXPORTBANNER); } /** * Getter for the <code>PROPERTY_STRING_EXPORTBANNER_SEPARATOR</code> property. * @return String */ public String getExportBannerSeparator() { return getProperty(PROPERTY_STRING_EXPORTBANNER_SEPARATOR); } /** * Getter for the <code>PROPERTY_BOOLEAN_SHOWHEADER</code> property. * @return boolean */ public boolean getShowHeader() { return getBooleanProperty(PROPERTY_BOOLEAN_SHOWHEADER); } /** * Getter for the <code>PROPERTY_STRING_EMPTYLIST_MESSAGE</code> property. * @return String */ public String getEmptyListMessage() { return getProperty(PROPERTY_STRING_EMPTYLIST_MESSAGE); } /** * Getter for the <code>PROPERTY_STRING_EMPTYLISTROW_MESSAGE</code> property. * @return String */ public String getEmptyListRowMessage() { return getProperty(PROPERTY_STRING_EMPTYLISTROW_MESSAGE); } /** * Getter for the <code>PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE</code> property. * @return boolean <code>true</code> if table should be displayed also if no items are found */ public boolean getEmptyListShowTable() { return getBooleanProperty(PROPERTY_BOOLEAN_EMPTYLIST_SHOWTABLE); } /** * Getter for the <code>PROPERTY_STRING_EXPORTAMOUNT</code> property. * @return boolean <code>true</code> if <code>export.amount</code> is <code>list</code> */ public boolean getExportFullList() { return "list".equals(getProperty(PROPERTY_STRING_EXPORTAMOUNT)); //$NON-NLS-1$ } /** * Getter for the <code>PROPERTY_STRING_SORTAMOUNT</code> property. * @return boolean <code>true</code> if <code>sort.amount</code> is <code>list</code> */ public boolean getSortFullList() { return "list".equals(getProperty(PROPERTY_STRING_SORTAMOUNT)); //$NON-NLS-1$ } /** * Should paging banner be added before the table? * @return boolean */ public boolean getAddPagingBannerTop() { String placement = getProperty(PROPERTY_STRING_BANNER_PLACEMENT); return "top".equals(placement) || "both".equals(placement); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Should paging banner be added after the table? * @return boolean */ public boolean getAddPagingBannerBottom() { String placement = getProperty(PROPERTY_STRING_BANNER_PLACEMENT); return "bottom".equals(placement) || "both".equals(placement); //$NON-NLS-1$ //$NON-NLS-2$ } /** * Returns the appropriate css class for a table row. * @param rowNumber row number * @return the value of <code>PROPERTY_CSS_TR_EVEN</code> if rowNumber is even or <code>PROPERTY_CSS_TR_ODD</code> * if rowNumber is odd. */ public String getCssRow(int rowNumber) { return getProperty((rowNumber % 2 == 0) ? PROPERTY_CSS_TR_ODD : PROPERTY_CSS_TR_EVEN); } /** * Returns the appropriate css class for a sorted column header. * @param ascending <code>true</code> if column is sorded in ascending order. * @return the value of <code>PROPERTY_CSS_TH_SORTED_ASCENDING</code> if column is sorded in ascending order or * <code>PROPERTY_CSS_TH_SORTED_DESCENDING</code> if column is sorded in descending order. */ public String getCssOrder(boolean ascending) { return getProperty(ascending ? PROPERTY_CSS_TH_SORTED_ASCENDING : PROPERTY_CSS_TH_SORTED_DESCENDING); } /** * Returns the configured css class for a sorted column header. * @return the value of <code>PROPERTY_CSS_TH_SORTED</code> */ public String getCssSorted() { return getProperty(PROPERTY_CSS_TH_SORTED); } /** * Returns the configured css class for the main table tag. * @return the value of <code>PROPERTY_CSS_TABLE</code> */ public String getCssTable() { return getProperty(PROPERTY_CSS_TABLE); } /** * Returns the configured css class for a sortable column header. * @return the value of <code>PROPERTY_CSS_TH_SORTABLE</code> */ public String getCssSortable() { return getProperty(PROPERTY_CSS_TH_SORTABLE); } /** * Returns the configured list of media. * @return the value of <code>PROPERTY_EXPORTTYPES</code> */ public String[] getExportTypes() { String list = getProperty(PROPERTY_EXPORTTYPES); if (list == null) { return new String[0]; } return StringUtils.split(list); } /** * Returns the class responsible for the given export. * @param exportName export name * @return String classname */ public String getExportClass(String exportName) { return getProperty(PROPERTY_EXPORT_PREFIX + SEP + exportName + SEP + EXPORTPROPERTY_STRING_CLASS); } /** * Returns an instance of configured requestHelperFactory. * @return RequestHelperFactory instance. * @throws FactoryInstantiationException if unable to load or instantiate the configurated class. */ public RequestHelperFactory getRequestHelperFactoryInstance() throws FactoryInstantiationException { Object loadedObject = getClassPropertyInstance(PROPERTY_CLASS_REQUESTHELPERFACTORY); // should not be null, but avoid errors just in case... see DISPL-148 if (loadedObject == null) { return new DefaultRequestHelperFactory(); } try { return (RequestHelperFactory) loadedObject; } catch (ClassCastException e) { throw new FactoryInstantiationException(getClass(), PROPERTY_CLASS_REQUESTHELPERFACTORY, loadedObject .getClass() .getName(), e); } } /** * Returns an instance of configured DecoratorFactory. * @return DecoratorFactory instance. * @throws FactoryInstantiationException if unable to load or instantiate the configurated class. */ public DecoratorFactory getDecoratorFactoryInstance() throws FactoryInstantiationException { Object loadedObject = getClassPropertyInstance(PROPERTY_CLASS_DECORATORFACTORY); if (loadedObject == null) { return new DefaultDecoratorFactory(); } try { return (DecoratorFactory) loadedObject; } catch (ClassCastException e) { throw new FactoryInstantiationException(getClass(), PROPERTY_CLASS_DECORATORFACTORY, loadedObject .getClass() .getName(), e); } } public String getPaginationSortParam() { String result = getProperty(PROPERTY_STRING_PAGINATION_SORT_PARAM); if (result == null) { result = "sort"; } return result; } public String getPaginationPageNumberParam() { String result = getProperty(PROPERTY_STRING_PAGINATION_PAGE_NUMBER_PARAM); if (result == null) { result = "page"; } return result; } public String getPaginationSortDirectionParam() { String result = getProperty(PROPERTY_STRING_PAGINATION_SORT_DIRECTION_PARAM); if (result == null) { result = "dir"; } return result; } public String getPaginationSearchIdParam() { String result = getProperty(PROPERTY_STRING_PAGINATION_SEARCH_ID_PARAM); if (result == null) { result = "searchId"; } return result; } public String getPaginationAscValue() { String result = getProperty(PROPERTY_STRING_PAGINATION_ASC_VALUE); if (result == null) { result = "asc"; } return result; } public String getPaginationDescValue() { String result = getProperty(PROPERTY_STRING_PAGINATION_DESC_VALUE); if (result == null) { result = "desc"; } return result; } public boolean getPaginationSkipPageNumberInSort() { String s = getProperty(PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT); if (s == null) { return true; } else { return getBooleanProperty(PROPERTY_BOOLEAN_PAGINATION_SKIP_PAGE_NUMBER_IN_SORT); } } // </JBN> /** * Returns the configured resource provider instance. If necessary instantiate the resource provider from config and * then keep a cached instance. * @return I18nResourceProvider instance. * @see I18nResourceProvider */ public I18nResourceProvider geResourceProvider() { String className = getProperty(PROPERTY_CLASS_LOCALEPROVIDER); if (resourceProvider == null) { if (className != null) { try { Class classProperty = ReflectHelper.classForName(className); resourceProvider = (I18nResourceProvider) classProperty.newInstance(); log.info(Messages.getString("TableProperties.classinitializedto", //$NON-NLS-1$ new Object[]{ClassUtils.getShortClassName(I18nResourceProvider.class), className})); } catch (Throwable e) { log.warn(Messages.getString("TableProperties.errorloading", //$NON-NLS-1$ new Object[]{ ClassUtils.getShortClassName(I18nResourceProvider.class), e.getClass().getName(), e.getMessage()})); } } else { log.info(Messages.getString("TableProperties.noconfigured", //$NON-NLS-1$ new Object[]{ClassUtils.getShortClassName(I18nResourceProvider.class)})); } // still null? if (resourceProvider == null) { // fallback provider, no i18n resourceProvider = new I18nResourceProvider() { // Always returns null public String getResource(String titleKey, String property, Tag tag, PageContext context) { return null; } }; } } return resourceProvider; } /** * Reads a String property. * @param key property name * @return property value or <code>null</code> if property is not found */ private String getProperty(String key) { return this.properties.getProperty(key); } /** * Sets a property. * @param key property name * @param value property value */ public void setProperty(String key, String value) { this.properties.setProperty(key, value); } /** * Reads a boolean property. * @param key property name * @return boolean <code>true</code> if the property value is "true", <code>false</code> for any other value. */ private boolean getBooleanProperty(String key) { return Boolean.TRUE.toString().equals(getProperty(key)); } /** * Returns an instance of a configured Class. Returns a configured Class instantiated * callingClass.forName([configuration value]). * @param key configuration key * @return instance of configured class * @throws FactoryInstantiationException if unable to load or instantiate the configurated class. */ private Object getClassPropertyInstance(String key) throws FactoryInstantiationException { Object instance = objectCache.get(key); if (instance != null) { return instance; } String className = getProperty(key); // shouldn't be null, but better check it if (className == null) { return null; } try { Class classProperty = ReflectHelper.classForName(className); instance = classProperty.newInstance(); objectCache.put(key, instance); return instance; } catch (Exception e) { throw new FactoryInstantiationException(getClass(), key, className, e); } } /** * Reads an int property. * @param key property name * @param defaultValue default value returned if property is not found or not a valid int value * @return property value */ private int getIntProperty(String key, int defaultValue) { try { return Integer.parseInt(getProperty(key)); } catch (NumberFormatException e) { // Don't care, use default log.warn(Messages.getString("TableProperties.invalidvalue", //$NON-NLS-1$ new Object[]{key, getProperty(key), new Integer(defaultValue)})); } return defaultValue; } /** * Obtain the name of the decorator configured for a given media type. * @param thatEnum A media type * @return The name of the decorator configured for a given media type. */ public String getExportDecoratorName(MediaTypeEnum thatEnum) { return getProperty(PROPERTY_EXPORT_PREFIX + SEP + thatEnum + SEP + PROPERTY_EXPORT_DECORATOR_SUFFIX); } }