/* * Copyright 2014 - 2017 Blazebit. * * Licensed 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 com.blazebit.persistence.view; import com.blazebit.persistence.CriteriaBuilder; import com.blazebit.persistence.KeysetPage; import com.blazebit.persistence.PaginatedCriteriaBuilder; import com.blazebit.persistence.FullQueryBuilder; import java.util.*; /** * A {@linkplain EntityViewSetting} is a set of filters and sorters that can be * applied to a {@link CriteriaBuilder}. Filters and sorters are added for * entity view attribute names. It also supports pagination and optional * parameters. Optional parameters are only set on a criteria builder if they * are needed but not satisfied. * * @param <T> The type of the entity view * @param <Q> {@linkplain PaginatedCriteriaBuilder} if paginated, {@linkplain CriteriaBuilder} otherwise * @author Christian Beikov * @author Moritz Becker * @since 1.0.0 */ public final class EntityViewSetting<T, Q extends FullQueryBuilder<T, Q>> { private final Class<T> entityViewClass; private final String viewConstructorName; private final Object entityId; private final int firstResult; private final int maxResults; private final boolean paginated; private final Set<String> viewNamedFilters = new LinkedHashSet<String>(); private final Map<String, Sorter> attributeSorters = new LinkedHashMap<String, Sorter>(); private final Map<String, AttributeFilterActivation> attributeFilters = new LinkedHashMap<String, AttributeFilterActivation>(); private final Map<String, Object> optionalParameters = new HashMap<String, Object>(); private final Map<String, Object> properties = new HashMap<String, Object>(); private KeysetPage keysetPage; private boolean keysetPaginated; private EntityViewSetting(Class<T> entityViewClass, Object entityId, int maxResults, boolean paginate, String viewConstructorName) { this.entityViewClass = entityViewClass; this.viewConstructorName = viewConstructorName; this.entityId = entityId; this.firstResult = -1; this.maxResults = maxResults; this.paginated = paginate; } private EntityViewSetting(Class<T> entityViewClass, int firstResult, int maxResults, boolean paginate, String viewConstructorName) { if (firstResult < 0) { throw new IllegalArgumentException("Invalid negative value for firstResult"); } this.entityViewClass = entityViewClass; this.viewConstructorName = viewConstructorName; this.entityId = null; this.firstResult = firstResult; this.maxResults = maxResults; this.paginated = paginate; } /** * Like {@link EntityViewSetting#create(java.lang.Class, java.lang.String)} but with the <code>viewConstructorname</code> set to null. * * @param entityViewClass The entity view class that should be used for the object builder * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, CriteriaBuilder<T>> create(Class<T> entityViewClass) { return new EntityViewSetting<T, CriteriaBuilder<T>>(entityViewClass, 0, Integer.MAX_VALUE, false, null); } /** * Creates a new {@linkplain EntityViewSetting} that can be applied on * criteria builders. * * @param entityViewClass The entity view class that should be used for the object builder * @param viewConstructorName The name of the view constructor * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, CriteriaBuilder<T>> create(Class<T> entityViewClass, String viewConstructorName) { return new EntityViewSetting<T, CriteriaBuilder<T>>(entityViewClass, 0, Integer.MAX_VALUE, false, viewConstructorName); } /** * Like {@link EntityViewSetting#create(java.lang.Class, int, int, java.lang.String)} but with the <code>viewConstructorname</code> set to null. * * @param entityViewClass The entity view class that should be used for the object builder * @param firstResult The position of the first result to retrieve, numbered from 0 * @param maxResults The maximum number of results to retrieve * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, PaginatedCriteriaBuilder<T>> create(Class<T> entityViewClass, int firstResult, int maxResults) { return new EntityViewSetting<T, PaginatedCriteriaBuilder<T>>(entityViewClass, firstResult, maxResults, true, null); } /** * Like {@link EntityViewSetting#create(java.lang.Class, java.lang.Object, int, java.lang.String)} but with the <code>viewConstructorname</code> set to null. * * @param entityViewClass The entity view class that should be used for the object builder * @param entityId The id of the entity which should be located on a page * @param maxResults The maximum number of results to retrieve * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, PaginatedCriteriaBuilder<T>> create(Class<T> entityViewClass, Object entityId, int maxResults) { return new EntityViewSetting<T, PaginatedCriteriaBuilder<T>>(entityViewClass, entityId, maxResults, true, null); } /** * Creates a new {@linkplain EntityViewSetting} that can be applied on * criteria builders. * * @param entityViewClass The entity view class that should be used for the object builder * @param firstResult The position of the first result to retrieve, numbered from 0 * @param maxResults The maximum number of results to retrieve * @param viewConstructorName The name of the view constructor * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, PaginatedCriteriaBuilder<T>> create(Class<T> entityViewClass, int firstResult, int maxResults, String viewConstructorName) { return new EntityViewSetting<T, PaginatedCriteriaBuilder<T>>(entityViewClass, firstResult, maxResults, true, viewConstructorName); } /** * Creates a new {@linkplain EntityViewSetting} that can be applied on * criteria builders. * * @param entityViewClass The entity view class that should be used for the object builder * @param entityId The id of the entity which should be located on a page * @param maxResults The maximum number of results to retrieve * @param viewConstructorName The name of the view constructor * @param <T> The type of the entity view * @return A new entity view setting */ public static <T> EntityViewSetting<T, PaginatedCriteriaBuilder<T>> create(Class<T> entityViewClass, Object entityId, int maxResults, String viewConstructorName) { return new EntityViewSetting<T, PaginatedCriteriaBuilder<T>>(entityViewClass, entityId, maxResults, true, viewConstructorName); } /** * Returns the entity view class. * * @return The entity view class */ public Class<T> getEntityViewClass() { return entityViewClass; } /** * Returns the entity view constructor name. * * @return The entity view constructor name */ public String getViewConstructorName() { return viewConstructorName; } /** * The id of the entity which should be located on the page returned result. * Returns <code>null</code> if no pagination or a absolute first result will be applied. * * @return The id of the entity which should be located on a page * @see FullQueryBuilder#page(java.lang.Object, int) */ public Object getEntityId() { return entityId; } /** * The first result that the criteria builder should return. Returns 0 if no * pagination will be applied. Returns -1 if an entity id was supplied. * * @return The first result * @see FullQueryBuilder#page(int, int) */ public int getFirstResult() { return firstResult; } /** * The maximum number of results that the criteria builder should return. * Returns {@linkplain java.lang.Integer#MAX_VALUE} if no pagination will be * applied. * * @return The maximum number of results * @see FullQueryBuilder#page(int, int) */ public int getMaxResults() { return maxResults; } /** * Returns true if this entiy view setting applies pagination, false otherwise. * * @return True if this entiy view setting applies pagination, false otherwise */ public boolean isPaginated() { return paginated; } /** * Returns the key set of this setting. * * @return The key set of this setting */ public KeysetPage getKeysetPage() { return keysetPage; } /** * Sets the key set of this setting. * * @param keysetPage the new key set * @return this setting for chaining */ public EntityViewSetting<T, Q> withKeysetPage(KeysetPage keysetPage) { this.keysetPage = keysetPage; this.keysetPaginated = true; return this; } /** * Returns true if this setting is key set paginated. * * @return true if this setting is key set paginated */ public boolean isKeysetPaginated() { return keysetPaginated; } /** * Adds the given attribute sorters to the attribute sorters of this * setting. Note that the attribute sorter order is retained. * * @param attributeSorters The attribute sorters to add */ public void addAttributeSorters(Map<String, Sorter> attributeSorters) { this.attributeSorters.putAll(attributeSorters); } /** * Adds the given attribute sorter to the attribute sorters of this setting. * Note that the attribute sorter order is retained. * * @param attributeName The name of the attribute sorter * @param sorter The sorter for the attribute sorter */ public void addAttributeSorter(String attributeName, Sorter sorter) { this.attributeSorters.put(attributeName, sorter); } /** * Returns true if sorters have been added, otherwise false. * * @return true if sorters have been added, otherwise false */ public boolean hasAttributeSorters() { return !attributeSorters.isEmpty(); } /** * Returns a copy of the attribute sorters that have been added. * * @return The attribute sorters */ public Map<String, Sorter> getAttributeSorters() { return attributeSorters; } /** * Adds the given attribute filters to the attribute filters of this * setting. * * @param attributeFilters The attribute filters to add */ public void addAttributeFilters(Map<String, Object> attributeFilters) { for (Map.Entry<String, Object> attributeFilterEntry : attributeFilters.entrySet()) { addAttributeFilter(attributeFilterEntry.getKey(), attributeFilterEntry.getValue()); } } /** * Adds the attribute's default attribute filter to the attribute filters of this setting * or overwrites the filter value of an existing default attribute filter. * * @param attributeName The name of the attribute filter * @param filterValue The filter value for the attribute filter */ public void addAttributeFilter(String attributeName, Object filterValue) { checkExistingFiltersForAttribute(attributeName, AttributeFilter.DEFAULT_NAME); this.attributeFilters.put(attributeName, new AttributeFilterActivation(filterValue)); } /** * Adds the attribute's attribute filter with the given name to the attribute filters of this setting * or overwrites the filter value of an existing attribute filter with the same attribute name and filter name. * * @param attributeName The attribute name * @param filterName The filter name * @param filterValue The filter value for the attribute filter */ public void addAttributeFilter(String attributeName, String filterName, Object filterValue) { checkExistingFiltersForAttribute(attributeName, filterName); this.attributeFilters.put(attributeName, new AttributeFilterActivation(filterName, filterValue)); } private void checkExistingFiltersForAttribute(String attributeName, String attributeFilterName) { AttributeFilterActivation attributeFilterActivation = this.attributeFilters.get(attributeName); if (attributeFilterActivation != null) { if (!attributeFilterActivation.getAttributeFilterName().equals(attributeFilterName)) { throw new IllegalArgumentException("At most one active attribute filter per attribute is allowed! attributeName = '" + attributeName + "'"); } } } /** * Returns true if filters have been added, otherwise false. * * @return true if filters have been added, otherwise false */ public boolean hasAttributeFilters() { return !attributeFilters.isEmpty() ; } /** * Returns a copy of the attribute filters that have been added. * * @return The attribute filters */ public Map<String, AttributeFilterActivation> getAttributeFilters() { return attributeFilters; } /** * Enables and adds the view filter with the given name in this setting. * * @param filterName The name of the view filter */ public void addViewFilter(String filterName) { this.viewNamedFilters.add(filterName); } /** * Returns true if named filters for the view have been added, otherwise false. * * @return true if named filters for the view have been added, otherwise false */ public boolean hasViewFilters() { return !viewNamedFilters.isEmpty(); } /** * Returns a copy of the named filters for the view that have been added. * * @return The named filters for the view */ public Set<String> getViewFilters() { return viewNamedFilters; } /** * Adds the given optional parameters to the optional parameters of this * setting. * * @param optionalParameters The optional parameters to add */ public void addOptionalParameters(Map<String, Object> optionalParameters) { this.optionalParameters.putAll(optionalParameters); } /** * Adds the given optional parameter to the optional parameters of this * setting. * * @param parameterName The name of the optional parameter * @param value The value of the optional parameter */ public void addOptionalParameter(String parameterName, Object value) { this.optionalParameters.put(parameterName, value); } /** * Returns true if optional parameters have been added, otherwise false. * * @return true if optional parameters have been added, otherwise false */ public boolean hasOptionalParameters() { return !optionalParameters.isEmpty(); } /** * Returns a copy of the optional parameters that have been added. * * @return The optional parameters */ public Map<String, Object> getOptionalParameters() { return optionalParameters; } /** * Set a entity view property or hint. * If a property or hint is not recognized, it is silently ignored. * @param propertyName name of property or hint * @param value value for property or hint * @throws IllegalArgumentException if the second argument is * not valid for the implementation * @since 1.2.0 */ public void setProperty(String propertyName, Object value) { properties.put(propertyName, value); } /** * Get the properties and hints and associated values that are in effect * for the entity view setting. * @return map of properties and hints in effect for entity view stting * @since 1.2.0 */ public Map<String, Object> getProperties() { return Collections.unmodifiableMap(properties); } /** * @author Moritz Becker * @since 1.2.0 */ public static class AttributeFilterActivation { private final String attributeFilterName; private final Object filterValue; private AttributeFilterActivation(Object filterValue) { this(AttributeFilter.DEFAULT_NAME, filterValue); } private AttributeFilterActivation(String attributeFilterName, Object filterValue) { this.attributeFilterName = attributeFilterName; this.filterValue = filterValue; } public String getAttributeFilterName() { return attributeFilterName; } public Object getFilterValue() { return filterValue; } } }