/* * 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 de.unioninvestment.eai.portal.portlet.crud.domain.form; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; import com.vaadin.ui.UI; import de.unioninvestment.eai.portal.portlet.crud.config.AllFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.AnyFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.ComparisonFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.ContainsFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.CustomFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.EndsWithFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.EqualsFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.FilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.FormActionConfig; import de.unioninvestment.eai.portal.portlet.crud.config.GreaterFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.GreaterOrEqualFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.IncludeFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.LessFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.LessOrEqualFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.NotFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.NothingFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.RegExpFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.SQLFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.config.SearchConfig; import de.unioninvestment.eai.portal.portlet.crud.config.SearchTablesConfig; import de.unioninvestment.eai.portal.portlet.crud.config.StartsWithFilterConfig; import de.unioninvestment.eai.portal.portlet.crud.domain.exception.BusinessException; import de.unioninvestment.eai.portal.portlet.crud.domain.model.CheckBoxFormField; import de.unioninvestment.eai.portal.portlet.crud.domain.model.DataContainer; import de.unioninvestment.eai.portal.portlet.crud.domain.model.DataContainer.FilterPolicy; import de.unioninvestment.eai.portal.portlet.crud.domain.model.DateFormField; import de.unioninvestment.eai.portal.portlet.crud.domain.model.Form; import de.unioninvestment.eai.portal.portlet.crud.domain.model.FormAction; import de.unioninvestment.eai.portal.portlet.crud.domain.model.FormAction.ActionHandler; import de.unioninvestment.eai.portal.portlet.crud.domain.model.FormField; import de.unioninvestment.eai.portal.portlet.crud.domain.model.MultiOptionListFormField; import de.unioninvestment.eai.portal.portlet.crud.domain.model.OptionListFormField; import de.unioninvestment.eai.portal.portlet.crud.domain.model.Portlet; import de.unioninvestment.eai.portal.portlet.crud.domain.model.Table; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.All; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Any; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Contains; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.CustomFilter; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.CustomFilterFactory; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.EndsWith; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Equal; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Filter; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Greater; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Less; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Not; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.Nothing; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.RegExpFilter; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.SQLFilter; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.SQLWhereFactory; import de.unioninvestment.eai.portal.portlet.crud.domain.model.filter.StartsWith; import de.unioninvestment.eai.portal.portlet.crud.domain.search.SearchableTablesFinder; import de.unioninvestment.eai.portal.portlet.crud.domain.support.InitializingUI; import de.unioninvestment.eai.portal.support.vaadin.context.Context; import de.unioninvestment.eai.portal.support.vaadin.date.DateUtils; import de.unioninvestment.eai.portal.support.vaadin.support.NumberFormatter; /** * Implementiert die Suche in einer Tabelle abhängig von einer * Formulareinstellung. * * @author carsten.mjartan */ public class SearchFormAction implements ActionHandler { private final FormActionConfig actionConfig; private final Portlet portlet; private SQLWhereFactory whereFactory; private boolean requiresFilter; private int timeout = 0; private CustomFilterFactory customFilterFactory; /** * @param actionConfig * die Konfiguration zur Suche * @param portlet * das Portlet für die Auflösung von Element-IDs */ public SearchFormAction(FormActionConfig actionConfig, Portlet portlet) { this.actionConfig = actionConfig; this.portlet = portlet; SearchConfig searchConfig = actionConfig.getSearch(); if (searchConfig != null) { this.timeout = searchConfig.getTimeoutInSeconds(); this.requiresFilter = searchConfig.isRequiresFilter(); } } /** * @param seconds * die Timeoutzeit in Sekunden. */ public void setTimeout(int seconds) { if (seconds >= 0) { this.timeout = seconds; } } /** * @param whereFactory * Factory für SQL-Where-Filter. Wird bei der Initialisierung des * Scripting-Modells gesetzt. */ public void setWhereFactory(SQLWhereFactory whereFactory) { this.whereFactory = whereFactory; } @Override public void execute(Form form) { boolean hasFilter = form.hasFilter(); if (!requiresFilter || hasFilter) { List<Table> tables = findSearchableTables(form); for (Table table : tables) { if (policyAllowsFiltering(table)) { applyFiltersToTable(form, table); } } } else { throw new BusinessException("portlet.crud.search.filter.mandatory"); } } private boolean policyAllowsFiltering(Table table) { InitializingUI application = (InitializingUI) UI.getCurrent(); if (application != null && application.isInitializing()) { FilterPolicy policy = table.getContainer().getFilterPolicy(); if (policy == FilterPolicy.NOTHING || policy == FilterPolicy.NOTHING_AT_ALL) { return false; } } return true; } /** * Gibt an, ob ein Where-Filter existiert. * * @return ob ein Where-Filter existiert */ public boolean whereFilterExists() { if (actionConfig.getSearch() != null) { for (FilterConfig config : actionConfig.getSearch() .getApplyFilters().getFilters()) { if (config instanceof SQLFilterConfig) { return true; } } } return false; } private void applyFiltersToTable(Form form, Table table) { List<Filter> filters = createFilters(form, table); DataContainer container = table.getContainer(); if (this.timeout > 0) { container.replaceFilters(filters, false, true, this.timeout); } else { table.getContainer().replaceFilters(filters, false, true); } } /** * Erzeugt zu einer Tabelle passenden Filter. * * @param form * Formularmodel * @param table * Tabellenmodel * @return Filterliste */ List<Filter> createFilters(Form form, Table table) { List<Filter> filters; List<FilterConfig> filterConfigs = createFilterConfigs(form, table); filters = getExplicitFiltersForTable(form, table, filterConfigs); return filters; } List<FilterConfig> createFilterConfigs(Form form, Table table) { List<FilterConfig> filterConfigs; if (actionConfig.getSearch() != null && actionConfig.getSearch().getApplyFilters() != null) { filterConfigs = actionConfig.getSearch().getApplyFilters() .getFilters(); } else { filterConfigs = createDefaultConfig(form, table); } return filterConfigs; } private List<FilterConfig> createDefaultConfig(Form form, Table table) { List<FilterConfig> result = new ArrayList<FilterConfig>(); DataContainer container = table.getContainer(); for (FormField field : form.getFields()) { String fieldName = field.getName(); Class<?> columnType = container.getType(fieldName); if (columnType == null) { continue; } else if (field instanceof DateFormField || field instanceof OptionListFormField || field instanceof CheckBoxFormField || Number.class.isAssignableFrom(columnType)) { EqualsFilterConfig config = new EqualsFilterConfig(); config.setField(fieldName); config.setColumn(fieldName); result.add(config); } else { StartsWithFilterConfig config = new StartsWithFilterConfig(); config.setField(fieldName); config.setColumn(fieldName); result.add(config); } } return result; } private List<Filter> getExplicitFiltersForTable(Form form, Table table, List<FilterConfig> filterConfigs) { List<Filter> result = new ArrayList<Filter>(); DataContainer container = table.getContainer(); for (FilterConfig config : filterConfigs) { if (!filterMatchesTable(table, config)) { continue; } if (config instanceof ComparisonFilterConfig) { ComparisonFilterConfig comparisonFilterConfig = (ComparisonFilterConfig) config; FormField formField = form.getFields().get( comparisonFilterConfig.getField()); if (formField instanceof MultiOptionListFormField) { if (config instanceof EqualsFilterConfig) { EqualsFilterConfig equalsFilterConfig = (EqualsFilterConfig) config; MultiOptionListFormField multiSelectionFormField = (MultiOptionListFormField) form .getFields().get(equalsFilterConfig.getField()); List<Filter> filterList = new ArrayList<Filter>(); for (String value : multiSelectionFormField.getValues()) { filterList.add(new Equal(equalsFilterConfig .getColumn(), value)); } result.add(new Any(filterList)); continue; } else { throw new IllegalArgumentException( "Filter des Typs '" + config.getClass().getSimpleName() + "' kann nicht auf Multiselect-Felder angewendet werden"); } } String fieldValue = formField.getValue(); if (fieldValue == null || fieldValue.trim().equals("")) { continue; } String columnName = comparisonFilterConfig.getColumn(); Class<?> columnType = container.getType(columnName); if (columnType == null) { continue; } else if (String.class.isAssignableFrom(columnType)) { addGeneralFilterByConfig(result, config, fieldValue, columnName); } else if (Number.class.isAssignableFrom(columnType)) { NumberFormatter numberFormatter = new NumberFormatter( (NumberFormat) container.getFormat(columnName)); Locale locale = Context.getLocale(); @SuppressWarnings("unchecked") Number numberValue = numberFormatter.convertToModel( fieldValue, (Class<? extends Number>) columnType, locale); if (!addGeneralFilterByConfig(result, config, numberValue, columnName)) { throw new IllegalArgumentException( "Filter des Typs '" + config.getClass().getSimpleName() + "' kann nicht auf Number-Spalten angewendet werden"); } } else if (Date.class.isAssignableFrom(columnType) && formField instanceof DateFormField) { DateFormField dateFormField = (DateFormField) formField; addTemporalFilterByConfig(result, config, DateUtils.adjustDateType( dateFormField.getBeginDate(), columnType), DateUtils.adjustDateType( dateFormField.getEndDate(), columnType), columnName); } else { throw new IllegalArgumentException("Cannot filter column '" + columnName + ": Unkown column type '" + columnType + "'"); } } else if (config instanceof AnyFilterConfig) { List<Filter> explicitFiltersForTable = getExplicitFiltersForTable( form, table, ((AnyFilterConfig) config).getFilters()); if (explicitFiltersForTable.size() > 0) { result.add(new Any(explicitFiltersForTable)); } } else if (config instanceof AllFilterConfig) { List<Filter> subfilters = getExplicitFiltersForTable(form, table, ((AllFilterConfig) config).getFilters()); if (subfilters.size() > 0) { result.add(new All(subfilters)); } } else if (config instanceof NotFilterConfig) { List<Filter> subfilters = getExplicitFiltersForTable(form, table, ((NotFilterConfig) config).getFilters()); if (subfilters.size() > 0) { result.add(new Not(subfilters)); } } else if (config instanceof CustomFilterConfig) { CustomFilterConfig customFilterConfig = (CustomFilterConfig) config; CustomFilter filter = customFilterFactory .createCustomFilter(customFilterConfig); if (filter != null) { result.add(filter); } } else if (config instanceof SQLFilterConfig) { SQLFilterConfig sqlFilterConfig = (SQLFilterConfig) config; SQLFilter filter = whereFactory .createFilter(sqlFilterConfig.getColumn(), sqlFilterConfig.getWhere()); if (filter != null) { result.add(filter); } } else if (config instanceof IncludeFilterConfig) { IncludeFilterConfig includeFilterConfig = (IncludeFilterConfig) config; FormAction formAction = getActionForIncludeFilter(includeFilterConfig); SearchFormAction otherActionHandler = (SearchFormAction) formAction .getActionHandler(); List<Filter> filters = otherActionHandler.createFilters( formAction.getForm(), table); if (filters != null) { result.add(new All(filters)); } } } return result; } FormAction getActionForIncludeFilter(IncludeFilterConfig includeFilterConfig) { String id = ((FormActionConfig) includeFilterConfig.getAction()) .getId(); FormAction formAction = (FormAction) portlet.getElementById(id); return formAction; } private void addTemporalFilterByConfig(List<Filter> result, FilterConfig config, Date beginDate, Date endDate, String columnName) { if (config instanceof EqualsFilterConfig) { Filter beginFilter = new Greater(columnName, beginDate, true); Filter endFilter = new Less(columnName, endDate, false); result.add(new All(Arrays.asList(beginFilter, endFilter))); } else if (config instanceof GreaterOrEqualFilterConfig) { result.add(new Greater(columnName, beginDate, true)); } else if (config instanceof GreaterFilterConfig) { result.add(new Greater(columnName, endDate, true)); } else if (config instanceof LessOrEqualFilterConfig) { result.add(new Less(columnName, endDate, false)); } else if (config instanceof LessFilterConfig) { result.add(new Less(columnName, beginDate, false)); } else { throw new IllegalArgumentException("Filter des Typs '" + config.getClass().getSimpleName() + "' kann nicht auf temporale Spalten angewendet werden"); } } boolean filterMatchesTable(Table table, FilterConfig config) { return config.getTable() == null || config.getTable().equals(table.getId()); } private boolean addGeneralFilterByConfig(List<Filter> result, FilterConfig config, Object fieldValue, String columnName) { if (config instanceof EqualsFilterConfig) { result.add(new Equal(columnName, fieldValue)); } else if (config instanceof GreaterFilterConfig) { result.add(new Greater(columnName, fieldValue, false)); } else if (config instanceof GreaterOrEqualFilterConfig) { result.add(new Greater(columnName, fieldValue, true)); } else if (config instanceof LessFilterConfig) { result.add(new Less(columnName, fieldValue, false)); } else if (config instanceof LessOrEqualFilterConfig) { result.add(new Less(columnName, fieldValue, true)); } else if (config instanceof StartsWithFilterConfig) { result.add(new StartsWith(columnName, (String) fieldValue, ((StartsWithFilterConfig) config).isCaseSensitive())); } else if (config instanceof EndsWithFilterConfig) { result.add(new EndsWith(columnName, (String) fieldValue, ((EndsWithFilterConfig) config).isCaseSensitive())); } else if (config instanceof ContainsFilterConfig) { result.add(new Contains(columnName, (String) fieldValue, ((ContainsFilterConfig) config).isCaseSensitive())); } else if (config instanceof RegExpFilterConfig) { String valueString = fieldValue == null ? null : fieldValue .toString(); result.add(new RegExpFilter(columnName, valueString, ((RegExpFilterConfig) config).getModifiers())); } else if (config instanceof NothingFilterConfig) { result.add(new Nothing()); } else { return false; } return true; } /** * Durchläuft des Modelbaum und liefert alle für die Suche nötigen * Tabellenkomponenten. * * @param form * - das aktuelle Formular als Ausgangspunkt für die Suche * @return - eine Liste aller relevanten Tabellen für die Suche. */ public List<Table> findSearchableTables(Form form) { SearchTablesConfig tables = actionConfig.getSearch() == null ? null : actionConfig.getSearch().getTables(); return new SearchableTablesFinder().findSearchableTables(form, tables); } public void setCustomFilterFactory(CustomFilterFactory filterFactory) { this.customFilterFactory = filterFactory; } }