/* * * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * * Copyright 2005 - 2008 Pentaho Corporation. All rights reserved. * * @created Aug 31, 2005 * @author James Dixon */ package org.pentaho.platform.uifoundation.component; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.dom4j.Element; import org.pentaho.commons.connection.IPentahoMetaData; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.platform.api.engine.ComponentException; import org.pentaho.platform.api.engine.ILogger; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.uifoundation.component.xml.FilterPanelException; import org.pentaho.platform.uifoundation.messages.Messages; import org.pentaho.platform.util.xml.XForm; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; /** * TODO sbarkdull, may be worth breaking into 4 separate classes, one for each of the ITEM_SOURCE_*'s * of course they would all implement the same interface or abstr class * A factory class would look at the xml, and create the appropriate instance/type * * @author unknow, probably James Dixon * */ abstract public class FilterDefinition { private static final String RE_HAS_WHITE_SPACE = ".+\\s+.+"; //$NON-NLS-1$ /** * the name of the title, identified by the element <title> in the filter panel definition file */ private String title; private String elementName; /** * a resultSet containing the text and values for the items to be displayed in the filter panel's * control. The result set may be a scoped variable, in which case it is retrieved by the key * specified in the <global-attribute> or <session-attribute> element in the filter panel * definition file. Or, it is the output of the action sequence, in which case it is retrieved * from the action sequence's output specified by the name of the <data-output> element * of the filter panel definition file. */ private IPentahoResultSet resultSet; /** * * the type of the control in the filter panel, identified by the element * <type> in the filter panel definition file. Valid values are: * radio,list,list-multi,check-multi,check-multi-scroll,check-multi-scroll-2-column, * check-multi-scroll-3-column,check-multi-scroll-4-column */ private int type; /** * name of the column to retrieve the names of the items placed in the filter panel's control * related to the member variable nameColumnNo */ protected String descriptionItem; /** * name of the column to retrieve the values of the items placed in the filter panel's control * related to the member variable valueColumnNo */ protected String valueItem; private String[] defaultValue; protected Element node; protected String formName; protected ILogger logger; protected IPentahoSession session; /** * index of the column to retrieve the names of the items placed in the filter panel's control * related to the member variable descriptionItem */ private int nameColumnNo = -1; /** * index of the column to retrieve the values of the items placed in the filter panel's control * related to the member variable valueItem */ private int valueColumnNo = -1; /** * Ctor, duh. * @param node * @param formName * @param logger */ protected FilterDefinition(final Element node, final IPentahoSession session, final ILogger logger) { this.logger = logger; this.node = node; this.session = session; } // public void setFormName(String formName) { // this.formName = formName; // } public String getTitle() { return title; } public String getName() { return elementName; } /** * order of precedence: session-attribute, global-attribute, data-solution, static-list * @param xMLnode * @throws FilterPanelException */ public void fromXml(final Element xMLnode) throws FilterPanelException { title = XmlDom4JHelper.getNodeText("title", xMLnode); //$NON-NLS-1$ elementName = XmlDom4JHelper.getNodeText("name", xMLnode); //$NON-NLS-1$ descriptionItem = XmlDom4JHelper.getNodeText("data-display", xMLnode); //$NON-NLS-1$ valueItem = XmlDom4JHelper.getNodeText("data-value", xMLnode); //$NON-NLS-1$ formName = XmlDom4JHelper.getNodeText("name", xMLnode); //$NON-NLS-1$ String typeStr = XmlDom4JHelper.getNodeText("type", xMLnode); //$NON-NLS-1$ if ("radio".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_RADIO; } else if ("list".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_LIST; } else if ("list-multi".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_LIST_MULTI; } else if ("check-multi".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_CHECK_MULTI; } else if ("check-multi-scroll".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_CHECK_MULTI_SCROLL; } else if ("check-multi-scroll-2-column".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_CHECK_MULTI_SCROLL_2_COLUMN; } else if ("check-multi-scroll-3-column".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_CHECK_MULTI_SCROLL_3_COLUMN; } else if ("check-multi-scroll-4-column".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_CHECK_MULTI_SCROLL_4_COLUMN; } else if ("text-box".equalsIgnoreCase(typeStr)) { //$NON-NLS-1$ type = XForm.TYPE_TEXT; } else { type = XForm.TYPE_SELECT; } } public void setDefaultValue(final String[] defaultValue) { this.defaultValue = defaultValue; } public boolean isValid(final String[] values) { if (values == null) { return (false); } for (String element : values) { if (!isValid(element)) { return (false); } } return (true); } protected boolean isValid(final String value) { // this assume that the list of valid values does not have to be populated // This is a new field which let the user specify whether an empty value is a valide value or not String empty = XmlDom4JHelper.getNodeText("empty-accepted", node); //$NON-NLS-1$ // This is a new field which let the user specify if the value select has to be in the list or values or not String valueInList = XmlDom4JHelper.getNodeText("value-in-list", node); //$NON-NLS-1$ boolean isEmptyAccepted = Boolean.parseBoolean(empty); boolean mustExistInList = ((valueInList != null) && (valueInList.length() > 0)) ? Boolean.parseBoolean(valueInList) : true; if (mustExistInList) { if (value == null) { return false; } if (resultSet == null) { // we cannot determin the values for this filter return false; } Object row[] = resultSet.next(); String rowValue; while (row != null) { rowValue = row[valueColumnNo].toString(); if (value.equals(rowValue)) { resultSet.close(); return true; } row = resultSet.next(); } // close the result set so we can loop through it again later if we need to resultSet.close(); return false; } else { if (isEmptyAccepted) { return true; } else { return ((value != null) && (value.length() > 0)); } } } // sbarkdull: doesn't appear to be used anywhere, temporarily removing it from the public interface /* private boolean isValid(String[] value, Map parameterProviders) { if (resultSet == null && parameterProviders != null) { populate(parameterProviders, value); } return isValid(value); } */ abstract protected IPentahoResultSet getResultSet(Map parameterProviders); public boolean populate(final Map parameterProviders, final String[] value) { // TODO apply session-based security // TODO support static lists of values defaultValue = value; resultSet = getResultSet(parameterProviders); if (resultSet != null) { // find the column that we have been told to you IPentahoMetaData metaData = resultSet.getMetaData(); nameColumnNo = metaData.getColumnIndex(descriptionItem); valueColumnNo = metaData.getColumnIndex(valueItem); } return (resultSet != null); } /** * Create the XForm header and XForm body, and place the results in the * parameters xformHeader and xformBody. * * @param xformHeader * StringBuffer containing the XForm header * @param xformBody * StringBuffer containing the XForm body * * @throws ComponentException * if this.nameColumnNo is -1, this.valueColumnNo is -1, or the * this.resultSet is null. nameColumnNo is likely to be -1 if * this.descriptionItem does not correlate with the value of * the <data-display> element in the filter panel definition * file and the name of a column in the resultSet. * valueColumnNo is likely to be -1 if this.valueItem does not * correlate with the value of the <data-value> element in * the filter panel definition file and the name of a column in * the resultSet. resultSet is likely to be null if a * result-set was not placed in session or global scope under * the key identified by the <global-attribute> or * <session-attribute> element in the filter panel definition * file, or if the action sequence identified by <data-action> * element in the filter panel definition file failed to return * a result set */ public void getXForm(final StringBuffer xformHeader, final StringBuffer xformBody) throws ComponentException { // iterate thru the values to get the items and the display names String value; String name; HashMap displayNames = null; ArrayList items = null; // TODO support multiple column headers / row headers // TODO support an iteration across columns for a given row // If the result is non-empty then we will extract the values from the result set and display to the user if ((resultSet != null) && (resultSet.getRowCount() > 0)) { displayNames = new HashMap(); items = new ArrayList(); if (nameColumnNo == -1) { // we did not find the specified name column throw new ComponentException(Messages.getInstance().getErrorString( "FilterDefinition.ERROR_0001_NAME_COLUMN_MISSING", descriptionItem)); //$NON-NLS-1$ } else if (valueColumnNo == -1) { // we did not find the specified name column throw new ComponentException(Messages.getInstance().getErrorString( "FilterDefinition.ERROR_0002_VALUE_COLUMN_MISSING", valueItem)); //$NON-NLS-1$ } else { // all is well with the world, you may proceed } Object row[] = null; try { row = resultSet.next(); } catch (Exception e) { // We will check for null below } if (row == null) { logger.warn(Messages.getInstance().getErrorString("FilterDefinition.ERROR_0004_FILTER_DEFINITION_EMPTY")); //$NON-NLS-1$ } else { while (row != null) { value = row[valueColumnNo].toString(); items.add(value); name = row[nameColumnNo].toString(); if (name != null) { displayNames.put(value, name); } row = resultSet.next(); } } // close the result set so we can loop through it again later if we need // to resultSet.close(); // now create the XForm for the item if (displayNames.size() == 0) { displayNames = null; } } else { // ResultSet is null and it is ok only for a filter type of TEXT_BOX if (type != XForm.TYPE_TEXT) { throw new ComponentException(Messages.getInstance().getErrorString("FilterDefinition.ERROR_0003_FILTER_DEFINITION_NULL")); //$NON-NLS-1$ } } assert formName != null : Messages.getInstance().getErrorString("FilterDefinition.ERROR_0005_NAME_ELEMENT_EMPTY"); //$NON-NLS-1$ assert !formName.matches(FilterDefinition.RE_HAS_WHITE_SPACE) : Messages.getInstance() .getErrorString("FilterDefinition.ERROR_0006_NAME_ELEMENT_WHITESPACE"); //$NON-NLS-1$ XForm.createXFormControl(type, elementName, defaultValue, items, displayNames, formName, xformHeader, xformBody); } public static void main(final String[] args) { String nm[] = { " xx", "xx ", " xx ", "x x", "xx", "custome rnumber", " x x " }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ for (String element : nm) { boolean matches = element.matches(FilterDefinition.RE_HAS_WHITE_SPACE); System.out.println("[" + element + "] matches: " + matches); //$NON-NLS-1$ //$NON-NLS-2$ } } }