org.locationtech.geogig.api.plumbing.diff.FeatureDiff.java Source code

Java tutorial

Introduction

Here is the source code for org.locationtech.geogig.api.plumbing.diff.FeatureDiff.java

Source

/* Copyright (c) 2013-2014 Boundless and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/edl-v10.html
 *
 * Contributors:
 * Victor Olaya (Boundless) - initial implementation
 */
package org.locationtech.geogig.api.plumbing.diff;

import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.locationtech.geogig.api.RevFeature;
import org.locationtech.geogig.api.RevFeatureType;
import org.opengis.feature.type.PropertyDescriptor;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.vividsolutions.jts.geom.Geometry;

/**
 * Defines the differences between 2 versions of the a given feature
 * 
 */
public class FeatureDiff {

    private Map<PropertyDescriptor, AttributeDiff> diffs;

    private String path;

    private RevFeatureType newFeatureType;

    private RevFeatureType oldFeatureType;

    public FeatureDiff(String path, Map<PropertyDescriptor, AttributeDiff> diffs, RevFeatureType oldFeatureType,
            RevFeatureType newFeatureType) {
        this.path = path;
        this.diffs = Maps.newHashMap(diffs);
        this.newFeatureType = newFeatureType;
        this.oldFeatureType = oldFeatureType;
    }

    /**
     * 
     * @param path the full path to the feature, including its name
     * @param newRevFeature the new version of the feature
     * @param oldRevFeature the old version of the feature
     * @param newRevFeatureType the new version of the feature type
     * @param oldRevFeatureType the old version of the feature type
     * @param all - true if all attributes should be added regardless of change
     */
    public FeatureDiff(String path, RevFeature newRevFeature, RevFeature oldRevFeature,
            RevFeatureType newRevFeatureType, RevFeatureType oldRevFeatureType, boolean all) {

        this.path = path;
        this.newFeatureType = newRevFeatureType;
        this.oldFeatureType = oldRevFeatureType;
        diffs = new HashMap<PropertyDescriptor, AttributeDiff>();

        ImmutableList<PropertyDescriptor> oldAttributes = oldRevFeatureType.sortedDescriptors();
        ImmutableList<PropertyDescriptor> newAttributes = newRevFeatureType.sortedDescriptors();
        ImmutableList<Optional<Object>> oldValues = oldRevFeature.getValues();
        ImmutableList<Optional<Object>> newValues = newRevFeature.getValues();
        BitSet updatedAttributes = new BitSet(newValues.size());
        for (int i = 0; i < oldAttributes.size(); i++) {
            Optional<Object> oldValue = oldValues.get(i);
            int idx = newAttributes.indexOf(oldAttributes.get(i));
            if (idx != -1) {
                Optional<Object> newValue = newValues.get(idx);
                if (!oldValue.equals(newValue) || all) {
                    if (Geometry.class.isAssignableFrom(oldAttributes.get(i).getType().getBinding())) {
                        diffs.put(oldAttributes.get(i),
                                new GeometryAttributeDiff(Optional.fromNullable((Geometry) oldValue.orNull()),
                                        Optional.fromNullable((Geometry) newValue.orNull())));
                    } else {
                        diffs.put(oldAttributes.get(i), new GenericAttributeDiffImpl(oldValue, newValue));
                    }
                }
                updatedAttributes.set(idx);
            } else {
                if (Geometry.class.isAssignableFrom(oldAttributes.get(i).getType().getBinding())) {
                    diffs.put(oldAttributes.get(i),
                            new GeometryAttributeDiff(Optional.fromNullable((Geometry) oldValue.orNull()),
                                    Optional.fromNullable((Geometry) null)));
                } else {
                    diffs.put(oldAttributes.get(i), new GenericAttributeDiffImpl(oldValue, null));
                }
            }
        }
        updatedAttributes.flip(0, newValues.size());
        for (int i = updatedAttributes.nextSetBit(0); i >= 0; i = updatedAttributes.nextSetBit(i + 1)) {
            if (Geometry.class.isAssignableFrom(newAttributes.get(i).getType().getBinding())) {
                diffs.put(newAttributes.get(i), new GeometryAttributeDiff(Optional.fromNullable((Geometry) null),
                        Optional.fromNullable((Geometry) newValues.get(i).orNull())));
            } else {
                diffs.put(newAttributes.get(i), new GenericAttributeDiffImpl(null, newValues.get(i)));
            }
        }

    }

    public boolean hasDifferences() {
        return diffs.size() != 0;
    }

    public Map<PropertyDescriptor, AttributeDiff> getDiffs() {
        return ImmutableMap.copyOf(diffs);
    }

    /**
     * Returns the full path to the feature, including its name
     * 
     * @return
     */
    public String getPath() {
        return path;
    }

    /**
     * The feature type of the new version of the feature
     * 
     * @return
     */
    public RevFeatureType getNewFeatureType() {
        return newFeatureType;
    }

    /**
     * The feature type of the old version of the feature
     * 
     * @return
     */
    public RevFeatureType getOldFeatureType() {
        return oldFeatureType;
    }

    /**
     * Returns a human-readable representation of this class. To get a string that can be used to
     * serialize this object, use the asText() method
     */
    public String toString() {

        StringBuilder sb = new StringBuilder();
        Set<Entry<PropertyDescriptor, AttributeDiff>> entries = diffs.entrySet();
        Iterator<Entry<PropertyDescriptor, AttributeDiff>> iter = entries.iterator();
        while (iter.hasNext()) {
            Entry<PropertyDescriptor, AttributeDiff> entry = iter.next();
            PropertyDescriptor pd = entry.getKey();
            AttributeDiff ad = entry.getValue();
            sb.append(pd.getName() + "\t" + ad.toString() + "\n");
        }
        return sb.toString();

    }

    /**
     * Returns a serialized text version of this object
     * 
     * @return
     */
    public String asText() {

        StringBuilder sb = new StringBuilder();
        Set<Entry<PropertyDescriptor, AttributeDiff>> entries = diffs.entrySet();
        Iterator<Entry<PropertyDescriptor, AttributeDiff>> iter = entries.iterator();
        while (iter.hasNext()) {
            Entry<PropertyDescriptor, AttributeDiff> entry = iter.next();
            PropertyDescriptor pd = entry.getKey();
            AttributeDiff ad = entry.getValue();
            sb.append(pd.getName().toString() + "\t" + ad.asText() + "\n");
        }
        return sb.toString();

    }

    /**
     * Returns a reversed version of the feature difference
     * 
     * @return
     */
    public FeatureDiff reversed() {
        Map<PropertyDescriptor, AttributeDiff> map = Maps.newHashMap();
        Set<Entry<PropertyDescriptor, AttributeDiff>> entries = diffs.entrySet();
        for (Iterator<Entry<PropertyDescriptor, AttributeDiff>> iterator = entries.iterator(); iterator
                .hasNext();) {
            Entry<PropertyDescriptor, AttributeDiff> entry = iterator.next();
            map.put(entry.getKey(), entry.getValue().reversed());

        }
        return new FeatureDiff(path, map, newFeatureType, oldFeatureType);
    }

    @Override
    public boolean equals(Object o) {
        // TODO: this is a temporary simple comparison. Should be more elaborate
        if (!(o instanceof FeatureDiff)) {
            return false;
        }
        FeatureDiff f = (FeatureDiff) o;
        return f.asText().equals(asText());
        // return f.diffs.equals(diffs) && f.path.equals(path);
    }

    /**
     * Checks whether a FeatureDiff conflicts with this one
     * 
     * @param featureDiff the featureDiff to check against this one
     */
    public boolean conflicts(FeatureDiff featureDiff) {
        Map<PropertyDescriptor, AttributeDiff> otherDiffs = featureDiff.diffs;
        for (PropertyDescriptor pd : otherDiffs.keySet()) {
            if (diffs.containsKey(pd)) {
                AttributeDiff ad = diffs.get(pd);
                AttributeDiff otherAd = otherDiffs.get(pd);
                if (ad.conflicts(otherAd)) {
                    return true;
                }
            }
        }
        return false;
    }
}