
uk.gov.gchq.gaffer.data.elementdefinition.view.ViewElementDefinition Maven / Gradle / Ivy
/*
* Copyright 2016-2020 Crown Copyright
*
* 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 uk.gov.gchq.gaffer.data.elementdefinition.view;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.common.collect.Sets;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import uk.gov.gchq.gaffer.commonutil.ToStringBuilder;
import uk.gov.gchq.gaffer.data.element.function.ElementAggregator;
import uk.gov.gchq.gaffer.data.element.function.ElementFilter;
import uk.gov.gchq.gaffer.data.element.function.ElementTransformer;
import uk.gov.gchq.gaffer.data.elementdefinition.ElementDefinition;
import uk.gov.gchq.gaffer.data.elementdefinition.exception.SchemaException;
import uk.gov.gchq.gaffer.exception.SerialisationException;
import uk.gov.gchq.gaffer.jsonserialisation.JSONSerialiser;
import uk.gov.gchq.koryphe.serialisation.json.SimpleClassNameIdResolver;
import uk.gov.gchq.koryphe.tuple.function.TupleAdaptedFunction;
import uk.gov.gchq.koryphe.tuple.predicate.TupleAdaptedPredicate;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* A {@code ViewElementDefinition} is an {@link ElementDefinition} containing
* transient properties, an {@link ElementTransformer} and two {@link ElementFilter}s.
*/
@JsonPropertyOrder(value = {
"preAggregationFilterFunctions",
"groupBy",
"aggregator",
"postAggregationFilterFunctions",
"transientProperties",
"transformFunctions",
"postTransformFilterFunctions",
"properties",
"excludeProperties"
}, alphabetic = true)
@JsonDeserialize(builder = ViewElementDefinition.Builder.class)
public class ViewElementDefinition implements ElementDefinition {
protected ElementFilter preAggregationFilter;
protected ElementFilter postAggregationFilter;
protected ElementAggregator aggregator;
protected ElementFilter postTransformFilter;
protected ElementTransformer transformer;
/**
* This field overrides the group by properties in the schema.
* They must be sub set of the group by properties in the schema.
* If the store is ordered, then it must be a truncated copy of the schema
* group by properties.
*
* If null, then the group by properties in the schema are used.
*
*
* If empty, then all group by properties are summarised.
*
*
* If 1 or more properties, then the specified properties are not
* summarised.
*
*/
protected Set groupBy;
protected Set properties;
protected Set excludeProperties;
/**
* Transient property map of property name to class.
*/
protected Map> transientProperties = new LinkedHashMap<>();
@JsonIgnore
public boolean isEmpty() {
return null == preAggregationFilter
&& null == postAggregationFilter
&& null == aggregator
&& null == transformer
&& null == postTransformFilter
&& null == groupBy
&& null == properties
&& null == excludeProperties
&& null == transientProperties;
}
public Set getGroupBy() {
return groupBy;
}
public void setGroupBy(final LinkedHashSet groupBy) {
this.groupBy = groupBy;
}
public Set getProperties() {
return properties;
}
public Set getExcludeProperties() {
return excludeProperties;
}
@JsonIgnore
public boolean isAllProperties() {
return null == properties && (null == excludeProperties || excludeProperties.isEmpty());
}
public boolean hasProperty(final String property) {
return properties.contains(property);
}
public Class> getTransientPropertyClass(final String propertyName) {
return transientProperties.get(propertyName);
}
@JsonIgnore
public Collection> getTransientPropertyClasses() {
return transientProperties.values();
}
@JsonIgnore
public Set getTransientProperties() {
return transientProperties.keySet();
}
public boolean containsTransientProperty(final String propertyName) {
return transientProperties.containsKey(propertyName);
}
/**
* @return the transient property map. {@link LinkedHashMap} of transient property name to class name.
*/
@JsonIgnore
public Map> getTransientPropertyMap() {
return transientProperties;
}
@JsonGetter("transientProperties")
public Map getTransientPropertyMapWithClassNames() {
if (transientProperties.isEmpty()) {
return null;
}
Map propertyMap = new HashMap<>();
for (final Entry> entry : transientProperties.entrySet()) {
propertyMap.put(entry.getKey(), SimpleClassNameIdResolver.getSimpleClassName(entry.getValue()));
}
return propertyMap;
}
@JsonIgnore
public ElementFilter getPreAggregationFilter() {
return preAggregationFilter;
}
public List> getPreAggregationFilterFunctions() {
return null != preAggregationFilter ? preAggregationFilter.getComponents() : null;
}
public boolean hasPreAggregationFilters() {
return null != preAggregationFilter && !preAggregationFilter.getComponents().isEmpty();
}
public ElementAggregator getAggregator() {
return aggregator;
}
/**
* Sets the aggregator
*
* @param aggregator the aggregator to set.
* @deprecated a {@link ViewElementDefinition} should be constructed using the
* {@link uk.gov.gchq.gaffer.data.elementdefinition.view.ViewElementDefinition.Builder}.
*/
@Deprecated
public void setAggregator(final ElementAggregator aggregator) {
this.aggregator = aggregator;
}
@JsonIgnore
public ElementFilter getPostAggregationFilter() {
return postAggregationFilter;
}
public List> getPostAggregationFilterFunctions() {
return null != postAggregationFilter ? postAggregationFilter.getComponents() : null;
}
public boolean hasPostAggregationFilters() {
return null != postAggregationFilter && !postAggregationFilter.getComponents().isEmpty();
}
@JsonIgnore
public ElementFilter getPostTransformFilter() {
return postTransformFilter;
}
public List> getPostTransformFilterFunctions() {
return null != postTransformFilter ? postTransformFilter.getComponents() : null;
}
public boolean hasPostTransformFilters() {
return null != postTransformFilter && !postTransformFilter.getComponents().isEmpty();
}
@JsonIgnore
public ElementTransformer getTransformer() {
return transformer;
}
public List> getTransformFunctions() {
return null != transformer ? transformer.getComponents() : null;
}
@SuppressWarnings("CloneDoesntCallSuperClone")
@SuppressFBWarnings(value = "CN_IDIOM_NO_SUPER_CALL", justification = "Only inherits from Object")
@Override
public ViewElementDefinition clone() {
return new ViewElementDefinition.Builder().json(toJson(false)).build();
}
public byte[] toJson(final boolean prettyPrint, final String... fieldsToExclude) throws SchemaException {
try {
return JSONSerialiser.serialise(this, prettyPrint, fieldsToExclude);
} catch (final SerialisationException e) {
throw new SchemaException(e.getMessage(), e);
}
}
public byte[] toCompactJson() throws SchemaException {
return toJson(false);
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (null == obj || getClass() != obj.getClass()) {
return false;
}
final ViewElementDefinition that = (ViewElementDefinition) obj;
return new EqualsBuilder()
.append(transformer, that.transformer)
.append(preAggregationFilter, that.preAggregationFilter)
.append(postAggregationFilter, that.postAggregationFilter)
.append(postTransformFilter, that.postTransformFilter)
.append(groupBy, that.groupBy)
.append(transientProperties, that.transientProperties)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(7, 23)
.append(transformer)
.append(preAggregationFilter)
.append(postAggregationFilter)
.append(postTransformFilter)
.append(groupBy)
.append(transientProperties)
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("transformer", transformer)
.append("preAggregationFilter", preAggregationFilter)
.append("postAggregationFilter", postAggregationFilter)
.append("postTransformFilter", postTransformFilter)
.append("groupBy", groupBy)
.append("transientProperties", transientProperties)
.toString();
}
@Override
public void lock() {
if (null != groupBy) {
groupBy = Collections.unmodifiableSet(groupBy);
}
transientProperties = Collections.unmodifiableMap(transientProperties);
}
public abstract static class BaseBuilder> {
private final ViewElementDefinition elDef;
public BaseBuilder() {
this.elDef = new ViewElementDefinition();
}
protected BaseBuilder(final ViewElementDefinition elementDef) {
this.elDef = elementDef;
}
public CHILD_CLASS allProperties() {
elDef.properties = null;
elDef.excludeProperties = null;
return self();
}
@JsonSetter("properties")
public CHILD_CLASS properties(final Set properties) {
if (null != properties && null != elDef.excludeProperties && !elDef.excludeProperties.isEmpty()) {
throw new IllegalArgumentException("You cannot set both properties and excludeProperties");
}
elDef.properties = properties;
return self();
}
@JsonIgnore
public CHILD_CLASS properties(final String... properties) {
if (null != properties && null != elDef.excludeProperties && !elDef.excludeProperties.isEmpty()) {
throw new IllegalArgumentException("You cannot set both properties and excludeProperties");
}
if (null == properties) {
elDef.properties = null;
} else {
elDef.properties = Sets.newHashSet(properties);
}
return self();
}
@JsonSetter("excludeProperties")
public CHILD_CLASS excludeProperties(final Set excludeProperties) {
if (null != excludeProperties && !excludeProperties.isEmpty() && null != elDef.properties) {
throw new IllegalArgumentException("You cannot set both properties and excludeProperties");
}
elDef.excludeProperties = excludeProperties;
return self();
}
@JsonIgnore
public CHILD_CLASS excludeProperties(final String... excludeProperties) {
if (null != excludeProperties && excludeProperties.length > 0 && null != elDef.properties) {
throw new IllegalArgumentException("You cannot set both properties and excludeProperties");
}
if (null == excludeProperties) {
elDef.excludeProperties = null;
} else {
elDef.excludeProperties = Sets.newHashSet(excludeProperties);
}
return self();
}
public CHILD_CLASS transientProperty(final String propertyName, final Class> clazz) {
elDef.transientProperties.put(propertyName, clazz);
return self();
}
public CHILD_CLASS transientProperties(final Map> transientProperties) {
if (null == transientProperties) {
elDef.transientProperties = new LinkedHashMap<>();
} else {
elDef.transientProperties = new LinkedHashMap<>(transientProperties);
}
return self();
}
public CHILD_CLASS preAggregationFilter(final ElementFilter preAggregationFilter) {
if (null != getElementDef().getPreAggregationFilter()) {
throw new IllegalArgumentException("ViewElementDefinition.Builder().preAggregationFilter(ElementFilter)" +
"may only be called once.");
}
getElementDef().preAggregationFilter = preAggregationFilter;
return self();
}
public CHILD_CLASS clearPreAggregationFilter() {
getElementDef().preAggregationFilter = null;
return self();
}
public CHILD_CLASS preAggregationFilterFunctions(final List> filterFunctions) {
getElementDef().preAggregationFilter = new ElementFilter();
if (null != filterFunctions) {
getElementDef().preAggregationFilter.getComponents().addAll(filterFunctions);
}
return self();
}
public CHILD_CLASS aggregator(final ElementAggregator aggregator) {
getElementDef().aggregator = aggregator;
return self();
}
public CHILD_CLASS clearAggregator() {
getElementDef().aggregator = null;
return self();
}
public CHILD_CLASS postAggregationFilter(final ElementFilter postAggregationFilter) {
if (null != getElementDef().getPostAggregationFilter()) {
throw new IllegalArgumentException("ViewElementDefinition.Builder().postAggregationFilter(ElementFilter)" +
"may only be called once.");
}
getElementDef().postAggregationFilter = postAggregationFilter;
return self();
}
public CHILD_CLASS clearPostAggregationFilter() {
getElementDef().postAggregationFilter = null;
return self();
}
public CHILD_CLASS postAggregationFilterFunctions(final List> filterFunctions) {
getElementDef().postAggregationFilter = new ElementFilter();
if (null != filterFunctions) {
getElementDef().postAggregationFilter.getComponents().addAll(filterFunctions);
}
return self();
}
public CHILD_CLASS postTransformFilter(final ElementFilter postTransformFilter) {
if (null != getElementDef().getPostTransformFilter()) {
throw new IllegalArgumentException("ViewElementDefinition.Builder().postTransformFilter(ElementFilter)" +
"may only be called once.");
}
getElementDef().postTransformFilter = postTransformFilter;
return self();
}
public CHILD_CLASS clearPostTransformFilter() {
getElementDef().postTransformFilter = null;
return self();
}
public CHILD_CLASS postTransformFilterFunctions(final List> filterFunctions) {
getElementDef().postTransformFilter = new ElementFilter();
if (null != filterFunctions) {
getElementDef().postTransformFilter.getComponents().addAll(filterFunctions);
}
return self();
}
public CHILD_CLASS transformer(final ElementTransformer transformer) {
getElementDef().transformer = transformer;
return self();
}
public CHILD_CLASS transformFunctions(final List> transformFunctions) {
getElementDef().transformer = new ElementTransformer();
return addTransformFunctions(transformFunctions);
}
public CHILD_CLASS addTransformFunctions(final List> transformFunctions) {
if (null == getElementDef().transformer) {
getElementDef().transformer = new ElementTransformer();
}
if (null != transformFunctions) {
getElementDef().transformer.getComponents().addAll(transformFunctions);
}
return self();
}
public CHILD_CLASS clearTransform() {
getElementDef().transformer = null;
return self();
}
public CHILD_CLASS clearFunctions() {
clearPreAggregationFilter();
clearAggregator();
clearPostAggregationFilter();
clearTransform();
clearPostTransformFilter();
return self();
}
public CHILD_CLASS groupBy(final String... groupBy) {
if (null != groupBy) {
if (null == getElementDef().getGroupBy()) {
getElementDef().setGroupBy(new LinkedHashSet<>());
}
Collections.addAll(getElementDef().getGroupBy(), groupBy);
} else {
getElementDef().setGroupBy(null);
}
return self();
}
@JsonIgnore
public CHILD_CLASS json(final byte[] jsonBytes) throws SchemaException {
return json(jsonBytes, ViewElementDefinition.class);
}
@JsonIgnore
protected CHILD_CLASS json(final byte[] jsonBytes, final Class extends ViewElementDefinition> clazz) throws SchemaException {
if (null != jsonBytes) {
try {
merge(JSONSerialiser.deserialise(jsonBytes, clazz));
} catch (final SerialisationException e) {
throw new SchemaException("Unable to deserialise json", e);
}
}
return self();
}
public CHILD_CLASS merge(final ViewElementDefinition elementDef) {
if (null != elementDef) {
for (final Entry> entry : elementDef.getTransientPropertyMap().entrySet()) {
final String newProp = entry.getKey();
final Class> newPropClass = entry.getValue();
if (!getElementDef().transientProperties.containsKey(newProp)) {
getElementDef().transientProperties.put(newProp, newPropClass);
} else {
final Class> clazz = getElementDef().transientProperties.get(newProp);
if (!clazz.equals(newPropClass)) {
throw new SchemaException("Unable to merge schemas. Conflict of transient property classes for " + newProp
+ ". Classes are: " + clazz.getName() + " and " + newPropClass.getName());
}
}
}
if (null == getElementDef().preAggregationFilter) {
getElementDef().preAggregationFilter = elementDef.preAggregationFilter;
} else if (null != elementDef.preAggregationFilter) {
getElementDef().preAggregationFilter.getComponents().addAll(elementDef.preAggregationFilter.getComponents());
}
if (null == getElementDef().postAggregationFilter) {
getElementDef().postAggregationFilter = elementDef.postAggregationFilter;
} else if (null != elementDef.postAggregationFilter) {
getElementDef().postAggregationFilter.getComponents().addAll(elementDef.postAggregationFilter.getComponents());
}
if (null == getElementDef().postTransformFilter) {
getElementDef().postTransformFilter = elementDef.postTransformFilter;
} else if (null != elementDef.postTransformFilter) {
getElementDef().postTransformFilter.getComponents().addAll(elementDef.postTransformFilter.getComponents());
}
if (null == getElementDef().transformer) {
getElementDef().transformer = elementDef.transformer;
} else if (null != elementDef.transformer) {
getElementDef().transformer.getComponents().addAll(elementDef.transformer.getComponents());
}
if (null != elementDef.getGroupBy()) {
getElementDef().groupBy = new LinkedHashSet<>(elementDef.getGroupBy());
}
if (null != elementDef.getProperties()) {
properties(elementDef.getProperties());
}
if (null != elementDef.getExcludeProperties() && !elementDef.getExcludeProperties().isEmpty()) {
excludeProperties(elementDef.getExcludeProperties());
}
}
return self();
}
public ViewElementDefinition build() {
elDef.lock();
return elDef;
}
public ViewElementDefinition getElementDef() {
return elDef;
}
protected abstract CHILD_CLASS self();
}
@JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
public static final class Builder extends BaseBuilder {
public Builder() {
}
public Builder(final ViewElementDefinition viewElementDef) {
this();
merge(viewElementDef);
}
@Override
protected Builder self() {
return this;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy