uk.gov.gchq.gaffer.data.elementdefinition.view.View.java Source code

Java tutorial

Introduction

Here is the source code for uk.gov.gchq.gaffer.data.elementdefinition.view.View.java

Source

/*
 * Copyright 2016-2017 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.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import uk.gov.gchq.gaffer.commonutil.CommonConstants;
import uk.gov.gchq.gaffer.data.elementdefinition.ElementDefinitions;
import uk.gov.gchq.gaffer.data.elementdefinition.exception.SchemaException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * The <code>View</code> defines the {@link uk.gov.gchq.gaffer.data.element.Element}s to be returned for an operation.
 * A view should contain {@link uk.gov.gchq.gaffer.data.element.Edge} and {@link uk.gov.gchq.gaffer.data.element.Entity} types required and
 * for each group it can optionally contain an {@link uk.gov.gchq.gaffer.data.element.function.ElementFilter} and a
 * {@link uk.gov.gchq.gaffer.data.element.function.ElementTransformer}.
 * The {@link uk.gov.gchq.gaffer.function.FilterFunction}s within the ElementFilter describe the how the elements should be filtered.
 * The {@link uk.gov.gchq.gaffer.function.TransformFunction}s within ElementTransformer allow transient properties to be created
 * from other properties and identifiers.
 * It also contains any transient properties that are created in transform functions.
 *
 * @see Builder
 * @see uk.gov.gchq.gaffer.data.elementdefinition.view.ViewElementDefinition
 * @see uk.gov.gchq.gaffer.data.element.function.ElementFilter
 * @see uk.gov.gchq.gaffer.data.element.function.ElementTransformer
 */
@JsonDeserialize(builder = View.Builder.class)
public class View extends ElementDefinitions<ViewElementDefinition, ViewElementDefinition> implements Cloneable {
    public List<GlobalViewElementDefinition> globalElements;
    public List<GlobalViewElementDefinition> globalEntities;
    public List<GlobalViewElementDefinition> globalEdges;

    public View() {
        super();
    }

    public static View fromJson(final InputStream inputStream) throws SchemaException {
        return new View.Builder().json(inputStream).build();
    }

    public static View fromJson(final Path filePath) throws SchemaException {
        return new View.Builder().json(filePath).build();
    }

    public static View fromJson(final byte[] jsonBytes) throws SchemaException {
        return new View.Builder().json(jsonBytes).build();
    }

    public byte[] toCompactJson() throws SchemaException {
        return toJson(false);
    }

    @Override
    public String toString() {
        try {
            return "View" + new String(toJson(true), CommonConstants.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public ViewElementDefinition getElement(final String group) {
        return (ViewElementDefinition) super.getElement(group);
    }

    public Set<String> getElementGroupBy(final String group) {
        ViewElementDefinition viewElementDef = (ViewElementDefinition) super.getElement(group);
        if (null == viewElementDef) {
            return null;
        }

        return viewElementDef.getGroupBy();
    }

    public List<GlobalViewElementDefinition> getGlobalElements() {
        return globalElements;
    }

    public List<GlobalViewElementDefinition> getGlobalEntities() {
        return globalEntities;
    }

    public List<GlobalViewElementDefinition> getGlobalEdges() {
        return globalEdges;
    }

    @SuppressWarnings("CloneDoesntCallSuperClone")
    @SuppressFBWarnings(value = "CN_IDIOM_NO_SUPER_CALL", justification = "Only inherits from Object")
    @Override
    public View clone() {
        return fromJson(toJson(false));
    }

    @Override
    protected void lock() {
        super.lock();
        if (null != globalElements) {
            globalElements = Collections.unmodifiableList(globalElements);
        }

        if (null != globalEntities) {
            globalEntities = Collections.unmodifiableList(globalEntities);
        }

        if (null != globalEdges) {
            globalEdges = Collections.unmodifiableList(globalEdges);
        }
    }

    /**
     * Copies all the global element definitions into the individual element definitions.
     * The global element definitions will then be set to null
     */
    public void expandGlobalDefinitions() {
        if (null != globalEntities && !globalEntities.isEmpty()) {
            setEntities(expandGlobalDefinitions(getEntities(), getEntityGroups(), globalEntities, false));
            globalEntities = null;
        }

        if (null != globalEdges && !globalEdges.isEmpty()) {
            setEdges(expandGlobalDefinitions(getEdges(), getEdgeGroups(), globalEdges, false));
            globalEdges = null;
        }

        if (null != globalElements && !globalElements.isEmpty()) {
            setEntities(expandGlobalDefinitions(getEntities(), getEntityGroups(), globalElements, true));
            setEdges(expandGlobalDefinitions(getEdges(), getEdgeGroups(), globalElements, true));
            globalElements = null;
        }
    }

    private Map<String, ViewElementDefinition> expandGlobalDefinitions(
            final Map<String, ViewElementDefinition> elements, final Set<String> groups,
            final List<GlobalViewElementDefinition> globalElements, final boolean skipMissingGroups) {

        final Map<String, ViewElementDefinition> newElements = new LinkedHashMap<>();
        for (final GlobalViewElementDefinition globalElement : globalElements) {
            final Set<String> globalGroups;
            if (null != globalElement.groups) {
                globalGroups = new HashSet<>(globalElement.groups);
                final boolean hasMissingGroups = globalGroups.retainAll(groups);
                if (hasMissingGroups) {
                    if (!skipMissingGroups) {
                        final Set<String> missingGroups = new HashSet<>(globalElement.groups);
                        missingGroups.removeAll(groups);
                        throw new IllegalArgumentException(
                                "A global element definition is invalid, these groups do not exist: "
                                        + missingGroups);
                    }
                }
            } else {
                globalGroups = groups;
            }
            for (final String group : globalGroups) {
                final ViewElementDefinition.Builder builder = new ViewElementDefinition.Builder();
                if (newElements.containsKey(group)) {
                    builder.merge(newElements.get(group));
                }
                builder.merge(globalElement.clone());
                newElements.put(group, builder.build());
            }
        }

        if (null != elements) {
            for (final Map.Entry<String, ViewElementDefinition> entry : elements.entrySet()) {
                final String group = entry.getKey();
                if (newElements.containsKey(group)) {
                    newElements.put(group, new ViewElementDefinition.Builder().merge(newElements.get(group))
                            .merge(entry.getValue()).build());
                } else {
                    newElements.put(group, entry.getValue());
                }
            }
        }

        return Collections.unmodifiableMap(newElements);
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final View view = (View) o;

        return new EqualsBuilder().appendSuper(super.equals(view)).append(globalElements, view.getGlobalElements())
                .append(globalEntities, view.getGlobalEntities()).append(globalEdges, view.getGlobalEdges())
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37).appendSuper(super.hashCode()).append(globalElements)
                .append(globalEntities).append(globalEdges).toHashCode();
    }

    public abstract static class BaseBuilder<CHILD_CLASS extends BaseBuilder<?>> extends
            ElementDefinitions.BaseBuilder<View, ViewElementDefinition, ViewElementDefinition, CHILD_CLASS> {
        public BaseBuilder() {
            super(new View());
        }

        protected BaseBuilder(final View view) {
            super(view);
        }

        @Override
        public CHILD_CLASS entity(final String group) {
            return entity(group, new ViewElementDefinition());
        }

        @Override
        public CHILD_CLASS edge(final String group) {
            return edge(group, new ViewElementDefinition());
        }

        public CHILD_CLASS globalElements(final GlobalViewElementDefinition... globalElements) {
            if (globalElements.length > 0) {
                if (null == getThisView().globalElements) {
                    getThisView().globalElements = new ArrayList<>();
                }
                Collections.addAll(getThisView().globalElements, globalElements);
            }
            return self();
        }

        public CHILD_CLASS globalEntities(final GlobalViewElementDefinition... globalEntities) {
            if (globalEntities.length > 0) {
                if (null == getThisView().globalEntities) {
                    getThisView().globalEntities = new ArrayList<>();
                }
                Collections.addAll(getThisView().globalEntities, globalEntities);
            }
            return self();
        }

        public CHILD_CLASS globalEdges(final GlobalViewElementDefinition... globalEdges) {
            if (globalEdges.length > 0) {
                if (null == getThisView().globalEdges) {
                    getThisView().globalEdges = new ArrayList<>();
                }
                Collections.addAll(getThisView().globalEdges, globalEdges);
            }
            return self();
        }

        @JsonIgnore
        public CHILD_CLASS json(final InputStream... inputStreams) throws SchemaException {
            return json(View.class, inputStreams);
        }

        @JsonIgnore
        public CHILD_CLASS json(final Path... filePaths) throws SchemaException {
            return json(View.class, filePaths);
        }

        @JsonIgnore
        public CHILD_CLASS json(final byte[]... jsonBytes) throws SchemaException {
            return json(View.class, jsonBytes);
        }

        @Override
        @JsonIgnore
        public CHILD_CLASS merge(final View view) {
            if (getThisView().getEntities().isEmpty()) {
                getThisView().getEntities().putAll(view.getEntities());
            } else {
                for (final Map.Entry<String, ViewElementDefinition> entry : view.getEntities().entrySet()) {
                    if (!getThisView().getEntities().containsKey(entry.getKey())) {
                        entity(entry.getKey(), entry.getValue());
                    } else {
                        final ViewElementDefinition mergedElementDef = new ViewElementDefinition.Builder()
                                .merge(getThisView().getEntities().get(entry.getKey())).merge(entry.getValue())
                                .build();
                        getThisView().getEntities().put(entry.getKey(), mergedElementDef);
                    }
                }
            }

            if (getThisView().getEdges().isEmpty()) {
                getThisView().getEdges().putAll(view.getEdges());
            } else {
                for (final Map.Entry<String, ViewElementDefinition> entry : view.getEdges().entrySet()) {
                    if (!getThisView().getEdges().containsKey(entry.getKey())) {
                        edge(entry.getKey(), entry.getValue());
                    } else {
                        final ViewElementDefinition mergedElementDef = new ViewElementDefinition.Builder()
                                .merge(getThisView().getEdges().get(entry.getKey())).merge(entry.getValue())
                                .build();
                        getThisView().getEdges().put(entry.getKey(), mergedElementDef);
                    }
                }
            }

            if (null != view.globalElements) {
                if (null == getThisView().globalElements) {
                    getThisView().globalElements = new ArrayList<>();
                }
                getThisView().globalElements.addAll(view.globalElements);
            }

            if (null != view.globalEntities) {
                if (null == getThisView().globalEntities) {
                    getThisView().globalEntities = new ArrayList<>();
                }
                getThisView().globalEntities.addAll(view.globalEntities);
            }

            if (null != view.globalEdges) {
                if (null == getThisView().globalEdges) {
                    getThisView().globalEdges = new ArrayList<>();
                }
                getThisView().globalEdges.addAll(view.globalEdges);
            }

            return self();
        }

        @Override
        public View build() {
            return super.build();
        }

        private View getThisView() {
            return getElementDefs();
        }
    }

    @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "")
    public static final class Builder extends BaseBuilder<Builder> {
        public Builder() {
        }

        public Builder(final View view) {
            this();
            merge(view);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }
}