package de.hft.unifiedticketing.core;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Filtered Ticket Request
*
* This class provides a builder like interface,
* to get a filtered list of Tickets.
*
* It provides some basic filter options by itself.
* The request logic has to be provided from each System specific
* implementation for it.
*
* @param The type of Ticket this Filter implementation delivers
* @param The type of the System specific implementation of this class
*/
public abstract class Filter>
{
private static Logger logger = Logging.getLogger(Filter.class.getName());
protected Map setFilters;// = new HashMap<>();
protected enum FilterNames
{
ASSIGNEEID,
ASSIGNEENAME,
DESCRIPTION_CONTAIN,
DESCRIPTION_MATCH,
IDS,
LABELS,
OPEN,
PAGE,
PAGINATION,
TITLE_CONTAINS,
TITLE_MATCH,
}
public Filter()
{
logger.log(Level.FINEST, String.format(
"%s request builder started",
this.getClass().getSimpleName()
));
setFilters = new HashMap<>();
}
/**
* Add assignee id to query
* @return this query builder
*/
public F withAssigneeId(String id)
{
addToSet(FilterNames.ASSIGNEEID, this.setFilters, id);
return (F) this;
}
/**
* Add assignee name to query
* @return this query builder
*/
public F withAssigneeName(String name)
{
addToSet(FilterNames.ASSIGNEENAME, this.setFilters, name);
return (F) this;
}
/**
* adds description contain constraint
* @param substring element to be contained in the description
* @return this query builder
*/
public F withDescriptionContain(String substring)
{
setFilters.put(FilterNames.DESCRIPTION_CONTAIN.name(), substring);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.DESCRIPTION_CONTAIN.name(), substring));
return (F) this;
}
/**
* regex that the whole description must match
* @param regex fully qualified regex
* @return this query builder
*/
public F withDescriptionMatch(String regex)
{
setFilters.put(FilterNames.DESCRIPTION_MATCH.name(), regex);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.DESCRIPTION_MATCH.name(), regex));
return (F) this;
}
/**
* adds an ticket id to the constraint list
* @param id
* @return this query builder
*/
public F withId(String id)
{
addToSet(FilterNames.IDS, this.setFilters, id);
return (F) this;
}
/**
* adds a constraint for only open considered tickets
* @return this query builder
*/
public F isOpen()
{
setFilters.put(FilterNames.OPEN.name(), true);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.OPEN.name(), true));
return (F) this;
}
/**
* adds a constraint for only closed considered tickets
* @return this query builder
*/
public F isClosed()
{
setFilters.put(FilterNames.OPEN.name(), false);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.OPEN.name(), false));
return (F) this;
}
/**
* add a label to the constraints list
*
* multiple calls of this delivers only tickets holding ALL given labels.
* @param label
* @return this query builder
*/
public F withLabel(String label)
{
addToSet(FilterNames.LABELS, this.setFilters, label);
return (F) this;
}
/**
* set the page number of the pagination
*
* Attention: some systems paginate by default.
* You can check that with {@link TicketSystem}s "has..." methods.
* @param page
* @return this query builder
*/
public F setPage(int page)
{
this.setFilters.put(FilterNames.PAGE.name(), page);
logger.log(Level.FINEST, String.format("set page: %d", page));
return (F) this;
}
/**
* defines the page size of a single pagination page
*
* Attention: some systems have a default in place, if nothing custom is set.
* You can check that with {@link TicketSystem}s "has..." methods.
* @param size
* @return this query builder
*/
public F setPageSize(int size)
{
this.setFilters.put(FilterNames.PAGINATION.name(), size);
logger.log(Level.FINEST, String.format("set pagination size: %d", size));
return (F) this;
}
/**
* adds a constraint for title containing the given string
* @param substring string the title must contain
* @return this query builder
*/
public F withTitleContain(String substring)
{
setFilters.put(FilterNames.TITLE_CONTAINS.name(), substring);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.TITLE_CONTAINS.name(), substring));
return (F) this;
}
/**
* adds a regex constraint, that the title has to match
* @param regex fully qualified regex
* @return this query builder
*/
public F withTitleMatch(String regex)
{
setFilters.put(FilterNames.TITLE_MATCH.name(), regex);
logger.log(Level.FINEST, String.format("added constraint: %s %s", FilterNames.TITLE_MATCH.name(), regex));
return (F) this;
}
/**
* Requesting the tickets
*
* This will prepare the request according to the system specific implementation,
* run the request, if needed post-filter the results and form it into a List
* @return List of Tickets, matching all previously set constraints
*/
public abstract List get();
protected static void addToSet(FilterNames filterName, Map map, String newValue)
{
logger.log(Level.FINEST, String.format("attempting to add new %s constraint", filterName.name()));
Set values;
if (map.containsKey(filterName.name()))
{
logger.log(Level.FINEST, String.format("existing %s constraints found", filterName.name()));
Object stored = map.get(filterName.name());
if (stored instanceof Set>)
{
values = (Set) stored;
} else
{
logger.log(Level.WARNING, String.format(
"found filter object under key %s was not from Type %s but %s",
filterName.name(),
Set.class.getName(),
stored.getClass().getName()));
values = new HashSet<>();
map.put(filterName.name(), values);
logger.log(Level.INFO, String.format(
"replaced wrong typed filter object under key %s with new instance of type %s",
filterName.name(),
Set.class.getName()));
}
} else
{
logger.log(Level.FINEST, String.format("no previous %s constraints found", filterName));
values = new HashSet<>();
map.put(filterName.name(), values);
}
values.add(newValue);
logger.log(Level.FINEST, String.format("added constraint: %s %s", filterName.name(), newValue));
}
}