Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ro.nextreports.server.web.report; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.datetime.markup.html.form.DateTextField; import org.apache.wicket.extensions.markup.html.form.palette.Palette; import org.apache.wicket.extensions.markup.html.form.palette.component.Recorder; import org.apache.wicket.extensions.yui.calendar.DateField; import org.apache.wicket.extensions.yui.calendar.DatePicker; import org.apache.wicket.extensions.yui.calendar.DateTimeField; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.html.panel.EmptyPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ro.nextreports.engine.Report; import ro.nextreports.engine.i18n.I18nLanguage; import ro.nextreports.engine.queryexec.IdName; import ro.nextreports.engine.queryexec.QueryParameter; import ro.nextreports.engine.util.DateUtil; import ro.nextreports.engine.util.ParameterUtil; import ro.nextreports.engine.util.StringUtil; import ro.nextreports.server.domain.DataSource; import ro.nextreports.server.domain.ReportRuntimeParameterModel; import ro.nextreports.server.report.next.NextRuntimeParameterModel; import ro.nextreports.server.service.DataSourceService; import ro.nextreports.server.service.ReportService; import ro.nextreports.server.service.StorageService; import ro.nextreports.server.util.ServerUtil; import ro.nextreports.server.web.common.misc.ExtendedPalette; /** * User: mihai.panaitescu * Date: 02-Feb-2010 * Time: 13:17:03 */ public abstract class ParameterRuntimePanel extends Panel { private static final long serialVersionUID = 1L; public static final String USER_PARAM = "__USER__"; @SpringBean protected StorageService storageService; @SpringBean protected ReportService reportService; @SpringBean protected DataSourceService dataSourceService; protected ParameterRuntimeModel runtimeModel; protected List<QueryParameter> paramList; private Map<String, QueryParameter> paramMap; private Map<QueryParameter, Component> paramComponentsMap; protected boolean runNow; private String errorMessage; // In Next, for source parameters default values are not the entire objects (id, name), but only the ids // so we will have to look at selection if the default values can be found in the list of the parameter values // and only if we found them we add them to the model // all dependent parameters that must be initialized after completing default values private transient List<QueryParameter> depParameters = new ArrayList<QueryParameter>(); // because dependent parameter values where not completed, also the default dependent values where not completed // and must be kept for further initialization private transient Map<QueryParameter, List<Serializable>> depDefValues = new HashMap<QueryParameter, List<Serializable>>(); private static final Logger LOG = LoggerFactory.getLogger(ParameterRuntimePanel.class); public ParameterRuntimePanel(String id) { this(id, true); } public ParameterRuntimePanel(String id, boolean runNow) { super(id); this.runNow = runNow; } public ParameterRuntimePanel(String id, ParameterRuntimeModel runtimeModel) { super(id); this.runNow = true; init(runtimeModel); } public abstract void addWicketComponents(); public abstract Report getNextReport(); public abstract I18nLanguage getLocaleLanguage(); public abstract DataSource getDataSource(); protected void init(ParameterRuntimeModel runtimeModel) { this.runtimeModel = runtimeModel; paramMap = ParameterUtil.getUsedNotHiddenParametersMap(getNextReport()); paramList = new ArrayList<QueryParameter>(paramMap.values()); paramComponentsMap = new HashMap<QueryParameter, Component>(); addComponents(); setOutputMarkupId(true); } protected void init(ParameterRuntimeModel runtimeModel, boolean fromGlobalModel) { this.runtimeModel = runtimeModel; paramMap = ParameterUtil.getUsedNotHiddenParametersMap(getNextReport()); // global settings : we may have less parameters (only common parameters) if (fromGlobalModel) { List<String> keys = new ArrayList<String>(); for (Iterator it = runtimeModel.getParameters().keySet().iterator(); it.hasNext();) { keys.add((String) it.next()); } for (Iterator it = paramMap.keySet().iterator(); it.hasNext();) { if (!keys.contains((String) it.next())) { it.remove(); } } } paramList = new ArrayList<QueryParameter>(paramMap.values()); paramComponentsMap = new HashMap<QueryParameter, Component>(); addComponents(); setOutputMarkupId(true); } private void addComponents() { // initialize model for some hidden hard-coded parameters // there is possible that a report can contain only hidden hard-coded parameters! for (QueryParameter parameter : ParameterUtil.getUsedHiddenParametersMap(getNextReport()).values()) { if ((USER_PARAM.equals(parameter.getName()))) { runtimeModel.getParameters().put(parameter.getName(), createRuntimeModel(parameter)); } } // initialize model for all not hidden parameters for (QueryParameter parameter : paramList) { if (!runtimeModel.isEdit()) { runtimeModel.getParameters().put(parameter.getName(), createRuntimeModel(parameter)); } } if (!runtimeModel.isEdit() && (errorMessage == null)) { // if some parameters initialized have default values, their dependent parameters // have to be initialized too for (QueryParameter qp : depParameters) { populateDependentParameters(qp, null, true); } } ListView<QueryParameter> listView = new ListView<QueryParameter>("params", new ArrayList<QueryParameter>(paramMap.values())) { private static final long serialVersionUID = 1L; @Override protected void populateItem(ListItem<QueryParameter> item) { createItem(item); } }; listView.setReuseItems(true); add(listView); addWicketComponents(); if (errorMessage != null) { error(errorMessage); } } @SuppressWarnings("unchecked") protected void createItem(ListItem<QueryParameter> item) { Component currentComponent = null; WebMarkupContainer paletteContainer = new WebMarkupContainer("paletteContainer"); final QueryParameter parameter = item.getModelObject(); final IModel generalModel = new PropertyModel(runtimeModel.getParameters(), parameter.getName() + ".rawValue"); IModel listModel = new PropertyModel(runtimeModel.getParameters(), parameter.getName() + ".valueList"); if (runtimeModel.isEdit()) { populateDependentParameters(parameter, null, true); } final TextField textField = new TextField("txtValue", generalModel); textField.setVisible(false); try { textField.setType(Class.forName(parameter.getValueClassName())); } catch (ClassNotFoundException e) { e.printStackTrace(); LOG.error(e.getMessage(), e); error(e.getMessage()); } final DateTimeField txtTime = new DateTimeField("txtTime", generalModel) { private static final long serialVersionUID = 1L; @Override public IModel<String> getLabel() { return new Model<String>(getParameterName(parameter)); } @Override protected boolean use12HourFormat() { return false; } @Override protected DateTextField newDateTextField(String id, PropertyModel dateFieldModel) { DateTextField f = super.newDateTextField(id, dateFieldModel); // Important must create a new ajaxUpdate behavior (otherwise an error will rise) // DateTextField uses newDateTextField method in constructor (DateField uses it in onBeforeRenderer method) // that's why for DateField is ok to use the same ajax which is added when component is made visible // for DateTextField ajax behavior is added even if the component is not visible! f.add(createAjax(parameter, generalModel, f)); return f; } protected DatePicker newDatePicker() { return new DatePicker() { private static final long serialVersionUID = 1L; @Override protected void configure(final Map<String, Object> widgetProperties, final IHeaderResponse response, final Map<String, Object> initVariables) { super.configure(widgetProperties, response, initVariables); } @Override protected boolean enableMonthYearSelection() { return true; } }; } }; // add ajax update behavior on hours and minutes textfields txtTime.get("hours").add(createAjax(parameter, generalModel, txtTime.get("hours"), "hours")); txtTime.get("minutes").add(createAjax(parameter, generalModel, txtTime.get("minutes"), "minutes")); txtTime.setVisible(false); final DateField txtDate = new DateField("txtDate", generalModel) { private static final long serialVersionUID = 1L; @Override public IModel<String> getLabel() { return new Model<String>(getParameterName(parameter)); } @Override protected DateTextField newDateTextField(java.lang.String id, PropertyModel dateFieldModel) { DateTextField f = super.newDateTextField(id, dateFieldModel); f.add(createAjax(parameter, generalModel, f)); return f; } protected DatePicker newDatePicker() { return new DatePicker() { private static final long serialVersionUID = 1L; @Override protected void configure(final Map<String, Object> widgetProperties, final IHeaderResponse response, final Map<String, Object> initVariables) { super.configure(widgetProperties, response, initVariables); } @Override protected boolean enableMonthYearSelection() { return true; } }; } }; txtDate.setVisible(false); final CheckBox chkBox = new CheckBox("chkBox", generalModel); chkBox.setVisible(false); DropDownChoice downChoice = new DropDownChoice("cmbValue", generalModel, new ArrayList<String>()); downChoice.setVisible(false); if (parameter.getSelection().equalsIgnoreCase(QueryParameter.SINGLE_SELECTION)) { if (parameter.getSource() != null && parameter.getSource().trim().length() > 0) { // combo downChoice = new DropDownChoice("cmbValue", generalModel, new LoadableDetachableModel() { @Override protected Object load() { // for combo default value can be a simple value or selected for a source (is not an IdName so we make it) // a default value from a manual source is an IdName Object obj = generalModel.getObject(); if ((obj != null) && !(obj instanceof IdName)) { IdName in = new IdName(); in.setId((Serializable) obj); in.setName((Serializable) obj); generalModel.setObject(in); } return runtimeModel.getParameters().get(parameter.getName()).getValues(); } }); if (!parameter.isHidden()) { if (parameter.isMandatory()) { downChoice.setRequired(true); } downChoice.setLabel(new Model<String>(getParameterName(parameter))); downChoice.setVisible(true); } // if parameter is not mandatory, even if we selected something by default, we should allow user to select null values if (!parameter.isMandatory()) { downChoice.setNullValid(true); } currentComponent = downChoice; } else { // not combo if (parameter.getValueClassName().contains("Date")) { if (!parameter.isHidden()) { if (generalModel.getObject() == null) { generalModel.setObject(DateUtil.floor(new Date())); } if (parameter.isMandatory()) { txtDate.setRequired(true); } txtDate.setVisible(true); } currentComponent = txtDate; } else if (parameter.getValueClassName().contains("Timestamp") || parameter.getValueClassName().contains("Time")) { if (!parameter.isHidden()) { if (generalModel.getObject() == null) { generalModel.setObject(DateUtil.floor(new Date())); } if (parameter.isMandatory()) { txtTime.setRequired(true); } txtTime.setVisible(true); } currentComponent = txtTime; } else if (parameter.getValueClassName().contains("Boolean")) { if (!parameter.isHidden()) { if (parameter.isMandatory()) { chkBox.setRequired(true); } chkBox.setLabel(new Model<String>(getParameterName(parameter))); chkBox.setVisible(true); } currentComponent = chkBox; } else { if (!parameter.isHidden()) { if (parameter.isMandatory()) { textField.setRequired(true); } textField.setLabel(new Model<String>(getParameterName(parameter))); textField.setVisible(true); } currentComponent = textField; } } paletteContainer.add(new EmptyPanel("palette")); } else { if (parameter.getSource() != null && parameter.getSource().trim().length() > 0) { if (!parameter.isHidden()) { Palette palette = createPalette(parameter, listModel, createAjax(parameter)); paletteContainer.add(palette.setOutputMarkupId(true)); currentComponent = palette; } else { paletteContainer.add(new EmptyPanel("palette")); } } else { ManualListPanel list = new ManualListPanel(parameter, listModel, 10, createAjax(parameter)); paletteContainer.add(list.setOutputMarkupId(true)); currentComponent = list; } } paramComponentsMap.put(parameter, currentComponent); // if this parameter has dependent parameters // we must update values for those using an ajax update // for Palette this is done in its class // for DateField and DateTimeField is done on the inner DateTextField if (ParameterUtil.getChildDependentParameters(getNextReport(), parameter).size() > 0) { boolean ajaxAlreadyAdded = (currentComponent instanceof Palette) || (currentComponent instanceof DateField) || (currentComponent instanceof DateTimeField); if (!ajaxAlreadyAdded) { currentComponent.add(createAjax(parameter)); } } String name = getDisplayableParameterName(parameter); Label lbl = new Label("name", name); lbl.setEscapeModelStrings(false); lbl.setOutputMarkupId(true); item.add(lbl); txtTime.setOutputMarkupId(true); item.add(txtTime); txtDate.setOutputMarkupId(true); item.add(txtDate); downChoice.setOutputMarkupId(true); item.add(downChoice); paletteContainer.setOutputMarkupId(true); item.add(paletteContainer); textField.setOutputMarkupId(true); item.add(textField); chkBox.setOutputMarkupId(true); item.add(chkBox); } private NextRuntimeParameterModel createRuntimeModel(QueryParameter parameter) { boolean isMultipleSelection = parameter.getSelection().equalsIgnoreCase(QueryParameter.MULTIPLE_SELECTION); NextRuntimeParameterModel runtimeModel = new NextRuntimeParameterModel(parameter.getName(), getParameterName(parameter), isMultipleSelection); runtimeModel.setMandatory(parameter.isMandatory()); List<IdName> values = new ArrayList<IdName>(); // set in the model only the values for parameters which are not dependent if ((errorMessage == null) && (parameter.getSource() != null) && (parameter.getSource().trim().length() > 0) && !parameter.isDependent()) { try { values = dataSourceService.getParameterValues(getDataSource(), parameter); } catch (Exception e) { e.printStackTrace(); errorMessage = "Get parameter values for : " + parameter.getName() + " > " + e.getMessage(); LOG.error(errorMessage, e); error(e.getMessage()); } } runtimeModel.setParameterValues(values); if (errorMessage == null) { initDefaultValues(runtimeModel, parameter, values); } return runtimeModel; } private void initDefaultValues(NextRuntimeParameterModel runtimeModel, QueryParameter parameter, List<IdName> values) { List<Serializable> defaultValues = new ArrayList<Serializable>(); if ((parameter.getDefaultValues() != null)) { defaultValues = parameter.getDefaultValues(); } if ((parameter.getDefaultSource() != null) && (parameter.getDefaultSource().trim().length() > 0)) { try { defaultValues = dataSourceService.getDefaultSourceValues(getDataSource(), parameter); } catch (Exception e) { e.printStackTrace(); errorMessage = "Get default source values for parameter : " + parameter.getName() + " > " + e.getMessage(); LOG.error(errorMessage, e); error(e.getMessage()); } } depDefValues.put(parameter, defaultValues); if (defaultValues.size() == 0) { return; } // for source parameters, the values are not entire objects (id, name) but only the ids // so we have to look in the parameter values for them if ((parameter.getSource() != null) && !parameter.getSource().trim().equals("")) { defaultValues = getSelectedValues(values, defaultValues); } if (defaultValues.size() == 0) { return; } boolean populateDependent = false; if (USER_PARAM.equals(parameter.getName())) { runtimeModel.setRawValue(ServerUtil.getUsernameWithoutRealm()); populateDependent = true; } else { if (QueryParameter.MULTIPLE_SELECTION.equals(parameter.getSelection())) { if (defaultValues.size() == 0) { runtimeModel.setValueList(new ArrayList<Object>()); } else { ArrayList<Object> list = new ArrayList<Object>(); list.addAll(defaultValues); runtimeModel.setValueList(list); populateDependent = true; } } else { if (defaultValues.size() > 0) { runtimeModel.setRawValue(defaultValues.get(0)); populateDependent = true; } } } // mark the dependent parameters that must be populated after initilize the default values if (populateDependent) { this.runtimeModel.getParameters().put(parameter.getName(), runtimeModel); depParameters.add(parameter); } } // a default value must be simple java object , or an IdName but only with the id private List<Serializable> getSelectedValues(List<IdName> values, List<Serializable> defaultValues) { List<Serializable> selectedValues = new ArrayList<Serializable>(); if (defaultValues == null) { return selectedValues; } for (Serializable s : defaultValues) { for (IdName in : values) { if (s instanceof IdName) { if ((in.getId() != null) && in.getId().equals(((IdName) s).getId())) { selectedValues.add(in); break; } } else if ((in.getId() != null) && in.getId().equals(s)) { selectedValues.add(in); break; } } } return selectedValues; } private List<Object> getSelectedValuesAsObject(List<Serializable> defaultValues) { List<Object> selectedValues = new ArrayList<Object>(); for (Serializable s : defaultValues) { selectedValues.add(s); } return selectedValues; } private AjaxFormComponentUpdatingBehavior createAjax(final QueryParameter parameter) { return new AjaxFormComponentUpdatingBehavior("onchange") { @Override protected void onUpdate(AjaxRequestTarget target) { populateDependentParameters(parameter, target, false); } }; } private AjaxFormComponentUpdatingBehavior createAjax(final QueryParameter parameter, final IModel model, final DateTextField dateField) { return new AjaxFormComponentUpdatingBehavior("onchange") { @SuppressWarnings("unchecked") @Override protected void onUpdate(AjaxRequestTarget target) { // @todo wicket 1.5 does not update model for DateField and DateTimeField // https://issues.apache.org/jira/browse/WICKET-4496 // use this as an workaround model.setObject(dateField.getDefaultModelObject()); populateDependentParameters(parameter, target, false); } }; } // @todo wicket 1.5 // used to update hours and minutes private AjaxFormComponentUpdatingBehavior createAjax(final QueryParameter parameter, final IModel model, final Component component, final String time) { return new AjaxFormComponentUpdatingBehavior("onchange") { @SuppressWarnings("unchecked") @Override protected void onUpdate(AjaxRequestTarget target) { // @todo wicket 1.5 does not update model for DateField and DateTimeField // https://issues.apache.org/jira/browse/WICKET-4496 // use this as an workaround if ((model == null) || (model.getObject() == null)) { return; } Date date = (Date) model.getObject(); if ("hours".equals(time)) { date = DateUtil.setHours(date, (Integer) component.getDefaultModelObject()); } else if ("minutes".equals(time)) { date = DateUtil.setMinutes(date, (Integer) component.getDefaultModelObject()); } model.setObject(date); populateDependentParameters(parameter, target, false); } }; } private void populateDependentParameters(QueryParameter parameter, AjaxRequestTarget target, boolean recursive) { Report nextReport = getNextReport(); if (nextReport == null) { return; } Map<String, QueryParameter> childParams = ParameterUtil.getChildDependentParameters(nextReport, parameter); // update model parameter values for every child parameter for (QueryParameter childParam : childParams.values()) { if (!paramList.contains(childParam)) { continue; } Component childComponent = paramComponentsMap.get(childParam); List<IdName> values = new ArrayList<IdName>(); boolean allParentsHaveValues = true; Map<String, QueryParameter> allParentParams = ParameterUtil.getParentDependentParameters(nextReport, childParam); for (QueryParameter parentParam : allParentParams.values()) { if (runtimeModel.getParameters().get(parentParam.getName()).getProcessingValue() == null) { allParentsHaveValues = false; break; } } if ((childParam.getSource() != null) && (childParam.getSource().trim().length() > 0) && allParentsHaveValues) { try { Map<String, Serializable> allParameterValues = new HashMap<String, Serializable>(); for (String name : runtimeModel.getParameters().keySet()) { ReportRuntimeParameterModel model = runtimeModel.getParameters().get(name); allParameterValues.put(model.getName(), (Serializable) model.getProcessingValue()); } //System.out.println("!!!! map = " + ParameterUtil.getDebugParameters(allParameterValues)); values = dataSourceService.getDependentParameterValues(getDataSource(), childParam, paramMap, allParameterValues); } catch (Exception e) { e.printStackTrace(); LOG.error("Get dependent parameter values for : " + childParam.getName() + " > " + e.getMessage(), e); error(e.getMessage()); } } NextRuntimeParameterModel parameterModel = (NextRuntimeParameterModel) runtimeModel.getParameters() .get(childParam.getName()); // if nothing is selected for that parameter (see scheduler) we look for the default values if ((parameterModel.getValueList() == null) || (parameterModel.getValueList().size() == 0)) { List<Serializable> list = getSelectedValues(values, depDefValues.get(childParam)); if (list.size() > 0) { parameterModel.setValueList(getSelectedValuesAsObject(list)); } } if (values != null && values.size() > 0) { parameterModel.setParameterValues(values); } else { parameterModel.setParameterValues(new ArrayList<IdName>()); } if (target != null) { target.add(childComponent); } if (recursive) { populateDependentParameters(childParam, target, true); } } } @SuppressWarnings("unchecked") private Palette createPalette(QueryParameter parameter, IModel listModel, AjaxFormComponentUpdatingBehavior ajaxUpdate) { ParameterPalette parameterPalette = new ParameterPalette(parameter, listModel, 10); parameterPalette.setUpdatingBehavior(ajaxUpdate); return parameterPalette; } private String getDisplayableParameterName(QueryParameter parameter) { if (parameter.isHidden()) { return ""; } String name = getParameterName(parameter); if (parameter.isMandatory()) { name += " <em>*</em>"; } return name; } private String getParameterName(QueryParameter parameter) { String name = parameter.getRuntimeName(); if ((name == null) || name.trim().equals("")) { name = parameter.getName(); } else { name = StringUtil.getI18nString(name, getLocaleLanguage()); } return name; } class ParameterPalette extends ExtendedPalette<Object> { private static final long serialVersionUID = 1L; private QueryParameter parameter; private AjaxFormComponentUpdatingBehavior updatingBehavior; public ParameterPalette(QueryParameter parameter, IModel<List<Object>> listModel, int rows) { //super("palette", listModel, new ParameterChoicesModel(parameter), new ParameterChoiceRenderer(), rows, false); super("palette", listModel, new ParameterChoicesModel(parameter), new ParameterChoiceRenderer(), rows, false, true); this.parameter = parameter; } public void setUpdatingBehavior(AjaxFormComponentUpdatingBehavior updatingBehavior) { this.updatingBehavior = updatingBehavior; } @Override protected Recorder<Object> newRecorderComponent() { Recorder<Object> recorder = super.newRecorderComponent(); String paramaterName = getParameterName(parameter); recorder.setLabel(new Model<String>(paramaterName)); if (!parameter.isHidden()) { if (parameter.isMandatory()) { recorder.setRequired(true); } } if (ParameterUtil.getChildDependentParameters(getNextReport(), parameter).size() > 0) { recorder.add(updatingBehavior); } return recorder; } } class ParameterChoicesModel extends LoadableDetachableModel<List<IdName>> { private static final long serialVersionUID = 1L; private QueryParameter parameter; public ParameterChoicesModel(QueryParameter parameter) { this.parameter = parameter; } @Override protected List<IdName> load() { String parameterName = parameter.getName(); List<IdName> list = runtimeModel.getParameters().get(parameterName).getValues(); return list.size() > 0 ? list : new ArrayList<IdName>(); } } class ParameterChoiceRenderer implements IChoiceRenderer<Object> { private static final long serialVersionUID = 1L; public Object getDisplayValue(Object object) { IdName value = (IdName) object; return (value.getName() == null) ? value.getId() : value.getName(); } public String getIdValue(Object object, int index) { if (object == null) { return ""; } if (!(object instanceof IdName)) { return object.toString(); } IdName value = (IdName) object; if (value.getId() == null) { return Integer.toString(index); } Object returnValue = value.getId(); if (returnValue == null) { return ""; } // IMPORTANT : if values start or end with space , on submit first rawValue will be ignored! // so we assure that the id never starts or ends with space! // // replace comma with other character (otherwise values with comma will be interpreted as two // values and no selection will be done for them) return "@" + returnValue.toString().replace(",", "-") + "@"; } } public boolean hasPalette() { for (QueryParameter parameter : paramList) { if (parameter.getSelection().equalsIgnoreCase(QueryParameter.MULTIPLE_SELECTION)) { if (parameter.getSource() != null && parameter.getSource().trim().length() > 0) { if (!parameter.isHidden()) { return true; } } } } return false; } }