/** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations under * the License. * * The Original Code is OpenELIS code. * * Copyright (C) The Minnesota Department of Health. All Rights Reserved. */ package us.mn.state.health.lims.taglib; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; import javax.servlet.jsp.JspException; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.taglib.TagUtils; import org.apache.struts.taglib.html.Constants; import org.apache.struts.taglib.html.SelectTag; import us.mn.state.health.lims.common.util.StringUtil; /** * @author benzd1 * * bugzilla 1844: extending OptionsCollectionTag to add toggling sort and label value * Test dropdown: display label as test.name dash test.description and allow toggling between * sorting by test.name and test.description. If sorting by test.description render labels * as alternateLabel (test.description dash test.name) property defined in * us.mn.state.health.lims.test.valueholder.Test */ public class SortableOptionsCollectionTag extends OptionsCollectionTag { private String filterProperty; private String filterValue; private String[] filterProperties = null; private String[] filterValues; private String matchProperty; private String matchValue; private String[] matchProperties = null; private String[] matchValues; private String allowEdits = "true"; private String showDefault = "true"; private String maxLength; private String sortFieldA; private String sortFieldB; private String alternateLabel; private static Log log = LogFactory.getLog(SortableOptionsCollectionTag.class); /** * Constructor for OptionsCollection. */ public SortableOptionsCollectionTag() { super(); } /** * Process the start of this tag. * * @exception JspException * if a JSP exception has occurred */ public int doStartTag() throws JspException { // Acquire the select tag we are associated with SelectTag selectTag = (SelectTag) pageContext .getAttribute(Constants.SELECT_KEY); if (selectTag == null) { JspException e = new JspException(messages .getMessage("optionsCollectionTag.select")); TagUtils.getInstance().saveException(pageContext, e); throw e; } // Acquire the collection containing our options Object collection = TagUtils.getInstance().lookup(pageContext, name, property, null); if (collection == null) { JspException e = new JspException(messages .getMessage("optionsCollectionTag.collection")); TagUtils.getInstance().saveException(pageContext, e); throw e; } // Acquire an iterator over the options collection Iterator iter = getIterator(collection); if (log.isDebugEnabled()) { log.debug("Filter Properties = " + filterProperty); } if (log.isDebugEnabled()) { log.debug("Filter Values = " + filterValue); } StringBuffer sb = new StringBuffer(); if (isAllowEdits() && isShowDefault()) { addOption(sb, "", "", false, "", "", ""); } boolean first = true; // Render the options while (iter.hasNext()) { Object bean = iter.next(); // Get the label for this option Object beanLabel = getProperty(bean, label); // Get the value for this option Object beanValue = getProperty(bean, value); Object beanSortFieldA = getProperty(bean, sortFieldA); Object beanSortFieldB = getProperty(bean, sortFieldB); Object beanAlternateLabel = getProperty(bean, alternateLabel); String stringLabel = beanLabel.toString(); String stringValue = beanValue.toString(); String stringSortFieldA = beanSortFieldA.toString(); String stringSortFieldB = beanSortFieldB.toString(); String stringAlternateLabel = beanAlternateLabel.toString(); boolean filterOkay = true; boolean matchOkay = true; Object beanFilter; // We only check the filter and match properties if the current // option is NOT a match. if (!selectTag.isMatched(stringValue)) { if (filterProperties != null) { for (int i = 0; i < filterProperties.length; ++i) { try { log.debug("Checking filter: " + filterProperties[i] + "=" + filterValues[i]); beanFilter = PropertyUtils.getNestedProperty(bean, filterProperties[i]); log.debug("Bean property: " + filterProperties[i] + "=" + beanFilter.toString()); } catch (Exception e) { throw new JspException( "Failed to retrieve property from bean.", e); } if (beanFilter != null && beanFilter.toString() .equals(filterValues[i])) { log.debug("Filter failed for " + filterProperties[i] + "."); // Filter failed, so break filterOkay = false; break; } } } if (matchProperties != null) { for (int i = 0; i < matchProperties.length; ++i) { try { log.debug("Checking filter: " + matchProperties[i] + "!=" + matchValues[i]); beanFilter = PropertyUtils.getNestedProperty(bean, matchProperties[i]); log.debug("Bean property: " + matchProperties[i] + "=" + beanFilter.toString()); } catch (Exception e) { throw new JspException( "Failed to retrieve property from bean.", e); } if (beanFilter != null && !beanFilter.toString() .equals(matchValues[i])) { log.debug("Match failed for " + matchProperties[i] + "."); // Match failed, so break matchOkay = false; break; } } } } if (filterOkay && matchOkay) { if (log.isDebugEnabled()) { log.debug("In OptionsTag label = " + stringLabel + " value = " + stringValue); } if (isAllowEdits()) { addOption(sb, stringLabel, stringValue, selectTag .isMatched(stringValue), stringSortFieldA, stringSortFieldB, stringAlternateLabel); } else { if (log.isDebugEnabled()) { log.debug("In OptionsTag is matched = " + selectTag.isMatched(stringValue)); } if (selectTag.isMatched(stringValue)) { if (!first) { stringLabel = ", " + stringLabel; } first = false; if (getStyleClass() != null) { stringLabel = "<span class=" + getStyleClass() + ">" + stringLabel + "</span>"; } sb.append(stringLabel); sb.append("\r\n<INPUT type=\"hidden\" name=\"" + selectTag.getProperty() + "\"" + " value=\"" + stringValue + "\"" + ">"); } } } } if (log.isDebugEnabled()) { log.debug("In OptionsTag output = " + sb.toString()); } // Render this element to our writer TagUtils.getInstance().write(pageContext, sb.toString()); return SKIP_BODY; } protected Object getProperty(Object bean, String property) throws JspException { // Get the value for this option Object beanValue = ""; try { beanValue = PropertyUtils.getProperty(bean, property); if (beanValue == null) { beanValue = ""; } } catch (IllegalAccessException e) { JspException jspe = new JspException(messages.getMessage( "getter.access", value, bean)); TagUtils.getInstance().saveException(pageContext, jspe); throw jspe; } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); JspException jspe = new JspException(messages.getMessage( "getter.result", value, t.toString())); TagUtils.getInstance().saveException(pageContext, jspe); throw jspe; } catch (NoSuchMethodException e) { JspException jspe = new JspException(messages.getMessage( "getter.method", value, bean)); TagUtils.getInstance().saveException(pageContext, jspe); throw jspe; } //adjusting handling of maxLength to not truncate in the middle of a word if (!StringUtil.isNullorNill(maxLength)) { try { int max = Integer.parseInt(maxLength); String beanVal = beanValue.toString(); if (beanVal.length() > max) { int indexOfNextSpaceForTruncation = beanVal.indexOf(" ", max); if (indexOfNextSpaceForTruncation >= 0) { beanValue = beanVal.substring(0, indexOfNextSpaceForTruncation); } else { //if we reach end of string before space we need to not cut off last word beanValue = beanVal.substring(0, beanVal.length()); } } } catch (Exception e) { // don't process maxLength if there is a problem } } return beanValue; } /** * Returns the filterProperty. * * @return String */ public String getFilterProperty() { return filterProperty; } /** * Returns the filterValue. * * @return String */ public String getFilterValue() { return filterValue; } /** * Sets the filterProperty. * * @param filterProperty * The filterProperty to set */ public void setFilterProperty(String filterProperty) { this.filterProperty = filterProperty; filterProperties = StringUtil.toArray(filterProperty); } /** * Sets the filterValue. * * @param filterValue * The filterValue to set */ public void setFilterValue(String filterValue) { this.filterValue = filterValue; filterValues = StringUtil.toArray(filterValue); } /** * Returns the matchProperty. * * @return String */ public String getMatchProperty() { return matchProperty; } /** * Returns the matchValue. * * @return String */ public String getMatchValue() { return matchValue; } /** * Sets the matchProperty. * * @param matchProperty * The matchProperty to set */ public void setMatchProperty(String matchProperty) { this.matchProperty = matchProperty; matchProperties = StringUtil.toArray(matchProperty); } /** * Sets the matchValue. * * @param matchValue * The matchValue to set */ public void setMatchValue(String matchValue) { this.matchValue = matchValue; matchValues = StringUtil.toArray(matchValue); } /** * Returns the allowEdits. * * @return boolean */ public String getAllowEdits() { return allowEdits; } /** * Returns the allowEdits. * * @return boolean */ public boolean isAllowEdits() { if (StringUtil.isNullorNill(getAllowEdits())) { return true; } return getAllowEdits().equals("true"); } /** * Sets the allowEdits. * * @param allowEdits * The allowEdits to set */ public void setAllowEdits(String allowEdits) { this.allowEdits = allowEdits; } public void setAllowEdits(boolean allowEdits) { this.allowEdits = (allowEdits ? "true" : "false"); } /** * Returns the showDefault. * * @return String */ public String getShowDefault() { return showDefault; } /** * Returns the showDefault. * * @return boolean */ public boolean isShowDefault() { if (StringUtil.isNullorNill(getShowDefault())) { return true; } return getShowDefault().equals("true"); } /** * Sets the showDefault. * * @param showDefault * The allowEdits to set */ public void setShowDefault(boolean showDefault) { this.showDefault = (showDefault ? "true" : "false"); } /** * Sets the showDefault. * * @param showDefault * The allowEdits to set */ public void setShowDefault(String showDefault) { this.showDefault = showDefault; } public String getMaxLength() { return maxLength; } public void setMaxLength(String maxLength) { this.maxLength = maxLength; } public String getSortFieldA() { return sortFieldA; } public void setSortFieldA(String sortFieldA) { this.sortFieldA = sortFieldA; } public String getSortFieldB() { return sortFieldB; } public void setSortFieldB(String sortFieldB) { this.sortFieldB = sortFieldB; } // ------------------------------------------------------ Protected Methods /** * Add an option element to the specified StringBuffer * benzd1 bugzilla 2293, 1844: overriding base addOption to include properties for sorting: type, sortFieldA, sortFieldB * * @param sb StringBuffer accumulating our results * @param value Value to be returned to the server for this option * @param label Value to be shown to the user for this option * @param matched Should this value be marked as selected? */ protected void addOption(StringBuffer sb, String label, String value, boolean matched, String sortFieldA, String sortFieldB, String alternateLabel) { sb.append("<option value=\""); if (filter) { sb.append(TagUtils.getInstance().filter(value)); } else { sb.append(value); } sb.append("\""); if (matched) { sb.append(" selected=\"selected\""); } if (getStyle() != null) { sb.append(" style=\""); sb.append(getStyle()); sb.append("\""); } if (getStyleClass() != null) { sb.append(" class=\""); sb.append(getStyleClass()); sb.append("\""); } if (sortFieldA != null) { sb.append(" sortFieldA=\""); sb.append(sortFieldA); sb.append("\""); } if (sortFieldB != null) { sb.append(" sortFieldB=\""); sb.append(sortFieldB); sb.append("\""); } if (alternateLabel != null) { sb.append(" alternateLabel=\""); sb.append(alternateLabel); sb.append("\""); } sb.append(">"); if (filter) { sb.append(TagUtils.getInstance().filter(label)); } else { sb.append(label); } sb.append("</option>\r\n"); } public String getAlternateLabel() { return alternateLabel; } public void setAlternateLabel(String alternateLabel) { this.alternateLabel = alternateLabel; } }