io.lavagna.service.SearchFilter.java Source code

Java tutorial

Introduction

Here is the source code for io.lavagna.service.SearchFilter.java

Source

/**
 * This file is part of lavagna.
 *
 * lavagna is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * lavagna 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with lavagna.  If not, see <http://www.gnu.org/licenses/>.
 */
package io.lavagna.service;

import static org.apache.commons.lang3.time.DateUtils.addDays;
import static org.apache.commons.lang3.time.DateUtils.addMonths;
import static org.apache.commons.lang3.time.DateUtils.addWeeks;
import static org.apache.commons.lang3.time.DateUtils.parseDateStrictly;
import static org.apache.commons.lang3.time.DateUtils.truncate;
import io.lavagna.model.ColumnDefinition;
import io.lavagna.model.UserWithPermission;
import io.lavagna.query.SearchQuery;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import lombok.AllArgsConstructor;
import lombok.Getter;

public class SearchFilter {

    private final FilterType type;
    private final String name;
    private final SearchFilterValue value;

    public static SearchFilter filter(FilterType type, ValueType valueType, Object value) {
        return new SearchFilter(type, null, new SearchFilterValue(valueType, value));
    }

    public static SearchFilter filterByColumnDefinition(ColumnDefinition value) {
        return filter(SearchFilter.FilterType.STATUS, SearchFilter.ValueType.STRING, value.toString());
    }

    public SearchFilter(FilterType type, String name, SearchFilterValue value) {
        this.type = type;
        this.name = name;
        this.value = value;
    }

    @Getter
    public static class SearchContext {
        private final UserWithPermission currentUser;
        private final Map<String, Integer> userNameToId;
        private final Map<String, Integer> cardNameToId;

        public SearchContext(UserWithPermission currentUser, Map<String, Integer> userNameToId,
                final Map<String, Integer> cardNameToId) {
            this.currentUser = currentUser;
            this.userNameToId = userNameToId;
            this.cardNameToId = cardNameToId;
        }
    }

    public enum FilterType {

        USER_LABEL {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                String r = queries.findByUserLabel();
                params.add(sf.name);
                if (sf.value == null) {
                    return r;
                }

                String val = sf.value.value.toString();
                // string
                params.add(val);
                // int
                params.add(tryParse(val));
                // timestamp from/to
                addDateParams(sf, params);
                // user
                params.add(from(context.userNameToId, val));
                // card
                params.add(from(context.cardNameToId, val));
                // list value
                params.add(val);

                return r + " " + queries.andLabelValueString();
            }

        },
        ASSIGNED {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {

                params.add("ASSIGNED");

                if (sf.value.type == ValueType.UNASSIGNED) {
                    return queries.findCardIdNotInOpen() + " " + queries.findBySystemLabel() + " "
                            + queries.findCardIdNotInClose();
                } else {
                    addUserToParam(context.currentUser, params, context.userNameToId, sf);
                    return queries.findBySystemLabel() + " " + queries.andLabelValueUser();
                }
            }
        },
        CREATED_BY {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                addUserToParam(context.currentUser, params, context.userNameToId, sf);
                return queries.findByCardCreationEventUser();
            }
        },
        CREATED {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {

                addDateParams(sf, params);

                return queries.findByCardCreationEventDate();
            }
        },
        WATCHED_BY {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add("WATCHED_BY");

                if (sf.value.type == ValueType.UNASSIGNED) {
                    return queries.findCardIdNotInOpen() + " " + queries.findBySystemLabel() + " "
                            + queries.findCardIdNotInClose();
                } else {
                    addUserToParam(context.currentUser, params, context.userNameToId, sf);
                    return queries.findBySystemLabel() + " " + queries.andLabelValueUser();
                }
            }
        },
        MILESTONE {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {

                params.add("MILESTONE");

                if (sf.value.type == ValueType.UNASSIGNED) {
                    return queries.findCardIdNotInOpen() + " " + queries.findBySystemLabel() + " "
                            + queries.findCardIdNotInClose();
                } else {
                    params.add(sf.value.value);
                    return queries.findBySystemLabel() + " " + queries.andLabelListValueEq();
                }

            }

        },

        DUE_DATE {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {

                params.add("DUE_DATE");

                addDateParams(sf, params);

                return queries.findBySystemLabel() + " " + queries.andLabelValueDate();
            }

        },

        STATUS {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add(sf.value.value);
                return queries.findByStatus();
            }
        },

        NOTLOCATION {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add(sf.value.value);
                return queries.findByNotLocation();
            }
        },

        LOCATION {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add(sf.value.value);
                return queries.findByLocation();
            }
        },

        UPDATED {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                addDateParams(sf, params);
                return queries.findByUpdated();
            }

        },

        UPDATED_BY {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                addUserToParam(context.currentUser, params, context.userNameToId, sf);
                return queries.findByUpdatedBy();
            }
        },

        BOARD_STATUS {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add(sf.value.value);
                return queries.findByBoardStatus();
            }
        },

        FREETEXT {
            @Override
            public String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                    SearchContext context) {
                params.add(sf.value.value);// for card sequence number
                params.add(sf.value.value);// for card name
                params.add(sf.value.value);// for card data
                return queries.findByFreeText();
            }
        };

        public abstract String toBaseQuery(SearchFilter sf, SearchQuery queries, List<Object> params,
                SearchContext context);

    }

    private static void addDateParams(SearchFilter sf, List<Object> params) {
        if (sf.value.type == ValueType.DATE_IDENTIFIER) {
            fromDateIdentifier(sf.value.value.toString(), params);
        } else {
            Date from = null, to = null;
            try {
                String[] splitted = sf.value.value.toString().split(Pattern.quote(".."));
                String[] format = { "dd.MM.yyyy", "dd-MM-yyyy", "dd/MM/yyyy", "yyyy-MM-dd", "yyyy.MM.dd",
                        "yyyy/MM/dd" };
                if (splitted.length == 2) {
                    from = truncate(parseDateStrictly(splitted[0], format), Calendar.DAY_OF_MONTH);
                    to = addDays(truncate(parseDateStrictly(splitted[1], format), Calendar.DAY_OF_MONTH), 1);
                } else {
                    from = truncate(parseDateStrictly(sf.value.value.toString(), format), Calendar.DAY_OF_MONTH);
                    to = addDays(from, 1);
                }
            } catch (ParseException pe) {
                //
            }
            params.add(from);
            params.add(to);
        }
    }

    // TODO: refactor/cleanup
    private static void fromDateIdentifier(String identifier, List<Object> params) {
        Date todayTruncated = truncate(new Date(), Calendar.DAY_OF_MONTH);
        Date beginMonth = truncate(new Date(), Calendar.MONTH);

        // TODO: internazionalization...
        Calendar c = truncate(Calendar.getInstance(), Calendar.DAY_OF_MONTH);
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        Date beginOfWeek = c.getTime();
        //

        switch (identifier) {
        case "late":
            params.add(new Date(0));
            params.add(todayTruncated);
            break;
        case "today":
            params.add(todayTruncated);
            params.add(addDays(todayTruncated, 1));
            break;
        case "yesterday":
            params.add(addDays(todayTruncated, -1));
            params.add(todayTruncated);
            break;
        case "tomorrow":
            params.add(addDays(todayTruncated, 1));
            params.add(addDays(todayTruncated, 2));
            break;
        case "this week":
            params.add(beginOfWeek);
            params.add(addWeeks(beginOfWeek, 1));
            break;
        case "this month":
            params.add(beginMonth);
            params.add(addMonths(beginMonth, 1));
            break;
        case "next week":
            params.add(addWeeks(beginOfWeek, 1));
            params.add(addWeeks(beginOfWeek, 2));
            break;
        case "next month":
            params.add(addMonths(beginMonth, 1));
            params.add(addMonths(beginMonth, 2));
            break;
        case "previous week":
            params.add(addWeeks(beginOfWeek, -1));
            params.add(beginOfWeek);
            break;
        case "previous month":
            params.add(addMonths(beginMonth, -1));
            params.add(beginMonth);
            break;
        case "last week":
            params.add(addDays(todayTruncated, -6));
            params.add(addDays(todayTruncated, 1));
            break;
        case "last month":
            params.add(addDays(todayTruncated, -29));
            params.add(addDays(todayTruncated, 1));
            break;
        default:
            break;
        }
    }

    public enum ValueType {
        BOOLEAN, STRING, CURRENT_USER, DATE_IDENTIFIER, UNASSIGNED
    }

    @Getter
    @AllArgsConstructor
    public static class SearchFilterValue {
        private final ValueType type;
        private final Object value;
    }

    private static void addUserToParam(UserWithPermission userWithPermission, List<Object> params,
            Map<String, Integer> userNameToId, SearchFilter searchFilter) {
        if (searchFilter.value.type == ValueType.CURRENT_USER && "me".equals(searchFilter.value.value)) {
            params.add(userWithPermission.getId());
        } else {
            params.add(from(userNameToId, searchFilter.value.value));
        }
    }

    private static Integer from(Map<String, Integer> f, Object key) {
        return key == null ? null : f.get(key);
    }

    private static Integer tryParse(String value) {
        try {
            return Integer.valueOf(value, 10);
        } catch (NullPointerException | NumberFormatException e) {
            return null;
        }
    }

    public FilterType getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public SearchFilterValue getValue() {
        return value;
    }

}