Package org.locationtech.geogig.api.plumbing.diff

Source Code of org.locationtech.geogig.api.plumbing.diff.Patch

/* 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.BitSet;
import java.util.List;

import org.locationtech.geogig.api.FeatureInfo;
import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.RevFeature;
import org.locationtech.geogig.api.RevFeatureBuilder;
import org.locationtech.geogig.api.RevFeatureType;
import org.locationtech.geogig.api.RevObject;
import org.locationtech.geogig.api.RevObject.TYPE;
import org.locationtech.geogig.storage.ObjectWriter;
import org.locationtech.geogig.storage.text.TextSerializationFactory;
import org.opengis.feature.Feature;
import org.opengis.feature.type.PropertyDescriptor;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

/**
* A patch that can be applied onto a working tree.
*
*/
public class Patch {

    private List<FeatureTypeDiff> alteredTrees;

    /**
     * Feature types needed to use the patch. This include those used by features involved, and aso
     * feature type that have been modified
     */
    private List<RevFeatureType> featureTypes;

    /**
     * features that have been edited
     */
    private List<FeatureDiff> modifiedFeatures;

    /**
     * features that have been added.
     */
    private List<FeatureInfo> addedFeatures;

    /**
     * features that have been removed
     */
    private List<FeatureInfo> removedFeatures;

    public Patch() {
        modifiedFeatures = Lists.newArrayList();
        removedFeatures = Lists.newArrayList();
        addedFeatures = Lists.newArrayList();
        featureTypes = Lists.newArrayList();
        alteredTrees = Lists.newArrayList();
    }

    /**
     * Returns a list of features modified by this patch
     *
     * @return
     */
    public List<FeatureDiff> getModifiedFeatures() {
        return ImmutableList.copyOf(modifiedFeatures);
    }

    /**
     * Returns a list of features added by this patch
     *
     * @return
     */
    public List<FeatureInfo> getAddedFeatures() {
        return ImmutableList.copyOf(addedFeatures);
    }

    /**
     * Returns a list of features modified by this patch
     *
     * @return
     */
    public List<FeatureInfo> getRemovedFeatures() {
        return ImmutableList.copyOf(removedFeatures);
    }

    /**
     * Adds a feature to the list of newly added ones
     *
     * @param path the path of the added feature
     * @param feature the feature
     * @param featureType the feature type of the added feature
     */
    public void addAddedFeature(String path, Feature feature, RevFeatureType featureType) {
        addedFeatures.add(new FeatureInfo(feature, featureType, path));
        addFeatureType(featureType);
    }

    /**
     * Adds a feature to the list of removed ones
     *
     * @param path the path of the removed feature
     * @param feature the feature
     * @param featureType the feature type of the removed feature
     */
    public void addRemovedFeature(String path, Feature feature, RevFeatureType featureType) {
        removedFeatures.add(new FeatureInfo(feature, featureType, path));
        addFeatureType(featureType);
    }

    /**
     * Adds an element to the list of modified ones
     *
     * @param diff
     */
    public void addModifiedFeature(FeatureDiff diff) {
        modifiedFeatures.add(diff);
        addFeatureType(diff.getNewFeatureType());
        addFeatureType(diff.getOldFeatureType());
    }

    /**
     * returns all the feature types used in this patch
     *
     * @return
     */
    public List<RevFeatureType> getFeatureTypes() {
        return ImmutableList.copyOf(featureTypes);
    }

    /**
     * Given an id, returns the feature type with that type, if it exist in the list of features
     * types affected by this patch
     *
     * @param id
     * @return
     */
    public Optional<RevFeatureType> getFeatureTypeFromId(ObjectId id) {
        for (RevFeatureType featureType : featureTypes) {
            if (featureType.getId().equals(id)) {
                return Optional.of(featureType);
            }
        }
        return Optional.absent();
    }

    /**
     * returns all the feature types modified by this patch
     *
     * @return
     */
    public ImmutableList<FeatureTypeDiff> getAlteredTrees() {
        return ImmutableList.copyOf(alteredTrees);
    }

    public void addAlteredTree(DiffEntry diff) {
        ObjectId oldFeatureType = diff.getOldObject() == null ? null : diff.getOldObject()
                .getMetadataId();
        ObjectId newFeatureType = diff.getNewObject() == null ? null : diff.getNewObject()
                .getMetadataId();
        String path = diff.oldPath() == null ? diff.newPath() : diff.oldPath();
        alteredTrees.add(new FeatureTypeDiff(path, oldFeatureType, newFeatureType));
    }

    public void addAlteredTree(FeatureTypeDiff diff) {
        alteredTrees.add(diff);
    }

    /**
     * Adds a new feature type to the list of them used in this patch
     *
     * @param featureType
     */
    public void addFeatureType(RevFeatureType featureType) {
        if (!featureTypes.contains(featureType)) {
            featureTypes.add(featureType);
        }
    }

    @Override
    public boolean equals(Object o) {
        // TODO: this is a temporary simple comparison. Should be more elaborate
        if (!(o instanceof Patch)) {
            return false;
        }
        Patch p = (Patch) o;
        return p.toString().equals(toString());
    }

    public boolean isEmpty() {
        return addedFeatures.isEmpty() && modifiedFeatures.isEmpty() && removedFeatures.isEmpty();
    }

    /**
     * This method is not intended to serialize the patch, as it misses some needed information. To
     * serialize the patch, use the {@link PatchSerializer} class instead. Use this method to show
     * patch content in a human-readable format
     */
    @Override
    public String toString() {
        TextSerializationFactory factory = new TextSerializationFactory();
        StringBuilder sb = new StringBuilder();
        for (FeatureInfo feature : addedFeatures) {
            String path = feature.getPath();
            sb.append("A\t" + path + "\t" + feature.getFeatureType().getId() + "\n");
            ObjectWriter<RevObject> writer = factory.createObjectWriter(TYPE.FEATURE);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            RevFeature revFeature = RevFeatureBuilder.build(feature.getFeature());
            try {
                writer.write(revFeature, output);
            } catch (IOException e) {
            }
            sb.append(output.toString());
            sb.append('\n');
        }
        for (FeatureInfo feature : removedFeatures) {
            String path = feature.getPath();
            sb.append("R\t" + path + "\t" + feature.getFeatureType().getId() + "\n");
            ObjectWriter<RevObject> writer = factory.createObjectWriter(TYPE.FEATURE);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            RevFeature revFeature = RevFeatureBuilder.build(feature.getFeature());
            try {
                writer.write(revFeature, output);
            } catch (IOException e) {
            }
            sb.append(output.toString());
            sb.append('\n');
        }
        for (FeatureDiff diff : modifiedFeatures) {
            sb.append("M\t" + diff.getPath() /*
                                              * + "\t" + diff.getOldFeatureType().getId().toString()
                                              * + "\t" + diff.getNewFeatureType().getId().toString()
                                              */+ "\n");
            sb.append(diff.toString() + "\n");
        }
        for (FeatureTypeDiff diff : alteredTrees) {
            sb.append(featureTypeDiffAsString(diff) + "\n");
        }
        return sb.toString();
    }

    private String featureTypeDiffAsString(FeatureTypeDiff diff) {
        StringBuilder sb = new StringBuilder();
        sb.append(diff.toString() + "\n");
        if (!diff.getNewFeatureType().equals(ObjectId.NULL)
                && !diff.getOldFeatureType().equals(ObjectId.NULL)) {
            RevFeatureType oldFeatureType = getFeatureTypeFromId(diff.getOldFeatureType()).get();
            RevFeatureType newFeatureType = getFeatureTypeFromId(diff.getNewFeatureType()).get();
            ImmutableList<PropertyDescriptor> oldDescriptors = oldFeatureType.sortedDescriptors();
            ImmutableList<PropertyDescriptor> newDescriptors = newFeatureType.sortedDescriptors();
            BitSet updatedDescriptors = new BitSet(newDescriptors.size());
            for (int i = 0; i < oldDescriptors.size(); i++) {
                PropertyDescriptor oldDescriptor = oldDescriptors.get(i);
                int idx = newDescriptors.indexOf(oldDescriptor);
                if (idx != -1) {
                    updatedDescriptors.set(idx);
                } else {
                    Class<?> oldType = oldDescriptor.getType().getBinding();
                    sb.append("R\t" + oldDescriptors.get(i).getName().getLocalPart() + "["
                            + oldType.getName() + "]");
                }

            }
            updatedDescriptors.flip(0, updatedDescriptors.length());
            for (int i = updatedDescriptors.nextSetBit(0); i >= 0; i = updatedDescriptors
                    .nextSetBit(i + 1)) {
                PropertyDescriptor newDescriptor = newDescriptors.get(i);
                Class<?> oldType = newDescriptor.getType().getBinding();
                sb.append("A\t" + newDescriptors.get(i).getName().getLocalPart() + "["
                        + oldType.getName() + "]");
            }
        }

        return sb.toString();
    }

    /**
     * Returns the total number of elements in this patch, whether added, removed or modified
     *
     * @return
     */
    public int count() {
        return addedFeatures.size() + removedFeatures.size() + modifiedFeatures.size()
                + alteredTrees.size();
    }

    /**
     * Returns the reversed version of the current patch. Applying this reversed patch has the
     * opposite effect to applying the original one, and can be used to undo changes
     *
     * @return a reversed version of this patch
     */
    public Patch reversed() {
        Patch patch = new Patch();
        patch.removedFeatures = addedFeatures;
        patch.addedFeatures = removedFeatures;
        for (FeatureDiff diff : modifiedFeatures) {
            patch.modifiedFeatures.add(diff.reversed());
        }
        for (FeatureTypeDiff diff : alteredTrees) {
            patch.alteredTrees.add(diff.reversed());
        }
        return patch;
    }

}
TOP

Related Classes of org.locationtech.geogig.api.plumbing.diff.Patch

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.