Search in sources :

Example 6 with FeatureInfo

use of org.locationtech.geogig.api.FeatureInfo in project GeoGig by boundlessgeo.

the class VerifyPatchOp method _call.

/**
     * Executes the verify command
     * 
     * @return the result of checking if the patch can be applied
     */
protected VerifyPatchResults _call() throws RuntimeException {
    Preconditions.checkArgument(patch != null, "No patch file provided");
    Patch patch = reverse ? this.patch.reversed() : this.patch;
    Patch toApply = new Patch();
    Patch toReject = new Patch();
    for (RevFeatureType ft : patch.getFeatureTypes()) {
        toApply.addFeatureType(ft);
        toReject.addFeatureType(ft);
    }
    String path;
    Optional<RevObject> obj;
    List<FeatureDiff> diffs = patch.getModifiedFeatures();
    for (FeatureDiff diff : diffs) {
        path = diff.getPath();
        String refSpec = Ref.WORK_HEAD + ":" + path;
        obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
        if (!obj.isPresent()) {
            toReject.addModifiedFeature(diff);
            break;
        }
        RevFeature feature = (RevFeature) obj.get();
        DepthSearch depthSearch = new DepthSearch(stagingDatabase());
        Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), path);
        RevFeatureType featureType = command(RevObjectParse.class).setObjectId(noderef.get().getMetadataId()).call(RevFeatureType.class).get();
        ImmutableList<PropertyDescriptor> descriptors = featureType.sortedDescriptors();
        Set<Entry<PropertyDescriptor, AttributeDiff>> attrDiffs = diff.getDiffs().entrySet();
        boolean ok = true;
        for (Iterator<Entry<PropertyDescriptor, AttributeDiff>> iterator = attrDiffs.iterator(); iterator.hasNext(); ) {
            Entry<PropertyDescriptor, AttributeDiff> entry = iterator.next();
            AttributeDiff attrDiff = entry.getValue();
            PropertyDescriptor descriptor = entry.getKey();
            switch(attrDiff.getType()) {
                case ADDED:
                    if (descriptors.contains(descriptor)) {
                        ok = false;
                    }
                    break;
                case REMOVED:
                case MODIFIED:
                    if (!descriptors.contains(descriptor)) {
                        ok = false;
                        break;
                    }
                    for (int i = 0; i < descriptors.size(); i++) {
                        if (descriptors.get(i).equals(descriptor)) {
                            Optional<Object> value = feature.getValues().get(i);
                            if (!attrDiff.canBeAppliedOn(value)) {
                                ok = false;
                            }
                            break;
                        }
                    }
            }
        }
        if (!ok) {
            toReject.addModifiedFeature(diff);
        } else {
            toApply.addModifiedFeature(diff);
        }
    }
    List<FeatureInfo> added = patch.getAddedFeatures();
    for (FeatureInfo feature : added) {
        String refSpec = Ref.WORK_HEAD + ":" + feature.getPath();
        obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
        if (obj.isPresent()) {
            toReject.addAddedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
        } else {
            toApply.addAddedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
        }
    }
    List<FeatureInfo> removed = patch.getRemovedFeatures();
    for (FeatureInfo feature : removed) {
        String refSpec = Ref.WORK_HEAD + ":" + feature.getPath();
        obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
        if (!obj.isPresent()) {
            toReject.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
        } else {
            RevFeature revFeature = (RevFeature) obj.get();
            DepthSearch depthSearch = new DepthSearch(stagingDatabase());
            Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), feature.getPath());
            RevFeatureType revFeatureType = command(RevObjectParse.class).setObjectId(noderef.get().getMetadataId()).call(RevFeatureType.class).get();
            RevFeature patchRevFeature = RevFeatureBuilder.build(feature.getFeature());
            if (revFeature.equals(patchRevFeature) && revFeatureType.equals(feature.getFeatureType())) {
                toApply.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
            } else {
                toReject.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
            }
        }
    }
    ImmutableList<FeatureTypeDiff> alteredTrees = patch.getAlteredTrees();
    for (FeatureTypeDiff diff : alteredTrees) {
        DepthSearch depthSearch = new DepthSearch(stagingDatabase());
        Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), diff.getPath());
        ObjectId metadataId = noderef.isPresent() ? noderef.get().getMetadataId() : ObjectId.NULL;
        if (Objects.equal(metadataId, diff.getOldFeatureType())) {
            toApply.addAlteredTree(diff);
        } else {
            toReject.addAlteredTree(diff);
        }
    }
    return new VerifyPatchResults(toApply, toReject);
}
Also used : FeatureInfo(org.locationtech.geogig.api.FeatureInfo) NodeRef(org.locationtech.geogig.api.NodeRef) Entry(java.util.Map.Entry) RevFeature(org.locationtech.geogig.api.RevFeature) RevFeatureType(org.locationtech.geogig.api.RevFeatureType) PropertyDescriptor(org.opengis.feature.type.PropertyDescriptor) RevObject(org.locationtech.geogig.api.RevObject) ObjectId(org.locationtech.geogig.api.ObjectId) DepthSearch(org.locationtech.geogig.repository.DepthSearch) RevObjectParse(org.locationtech.geogig.api.plumbing.RevObjectParse) RevObject(org.locationtech.geogig.api.RevObject)

Example 7 with FeatureInfo

use of org.locationtech.geogig.api.FeatureInfo in project GeoGig by boundlessgeo.

the class ReportMergeScenarioOp method _call.

@Override
protected MergeScenarioReport _call() {
    Optional<ObjectId> ancestor = command(FindCommonAncestor.class).setLeft(toMerge).setRight(mergeInto).call();
    Preconditions.checkState(ancestor.isPresent(), "No ancestor commit could be found.");
    Map<String, DiffEntry> mergeIntoDiffs = Maps.newHashMap();
    MergeScenarioReport report = new MergeScenarioReport();
    Iterator<DiffEntry> diffs = command(DiffTree.class).setOldTree(ancestor.get()).setReportTrees(true).setNewTree(mergeInto.getId()).call();
    while (diffs.hasNext()) {
        DiffEntry diff = diffs.next();
        String path = diff.oldPath() == null ? diff.newPath() : diff.oldPath();
        mergeIntoDiffs.put(path, diff);
    }
    Iterator<DiffEntry> toMergeDiffs = command(DiffTree.class).setOldTree(ancestor.get()).setReportTrees(true).setNewTree(toMerge.getId()).call();
    while (toMergeDiffs.hasNext()) {
        DiffEntry toMergeDiff = toMergeDiffs.next();
        String path = toMergeDiff.oldPath() == null ? toMergeDiff.newPath() : toMergeDiff.oldPath();
        if (mergeIntoDiffs.containsKey(path)) {
            RevCommit ancestorCommit = command(RevObjectParse.class).setRefSpec(ancestor.get().toString()).call(RevCommit.class).get();
            RevTree ancestorTree = command(RevObjectParse.class).setObjectId(ancestorCommit.getTreeId()).call(RevTree.class).get();
            Optional<NodeRef> ancestorVersion = command(FindTreeChild.class).setChildPath(path).setParent(ancestorTree).call();
            ObjectId ancestorVersionId = ancestorVersion.isPresent() ? ancestorVersion.get().getNode().getObjectId() : ObjectId.NULL;
            ObjectId theirs = toMergeDiff.getNewObject() == null ? ObjectId.NULL : toMergeDiff.getNewObject().objectId();
            DiffEntry mergeIntoDiff = mergeIntoDiffs.get(path);
            ObjectId ours = mergeIntoDiff.getNewObject() == null ? ObjectId.NULL : mergeIntoDiff.getNewObject().objectId();
            if (!mergeIntoDiff.changeType().equals(toMergeDiff.changeType())) {
                report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                continue;
            }
            switch(toMergeDiff.changeType()) {
                case ADDED:
                    if (toMergeDiff.getNewObject().equals(mergeIntoDiff.getNewObject())) {
                    // already added in current branch, no need to do anything
                    } else {
                        TYPE type = command(ResolveObjectType.class).setObjectId(toMergeDiff.getNewObject().objectId()).call();
                        if (TYPE.TREE.equals(type)) {
                            boolean conflict = !toMergeDiff.getNewObject().getMetadataId().equals(mergeIntoDiff.getNewObject().getMetadataId());
                            if (conflict) {
                                // In this case, we store the metadata id, not the element id
                                ancestorVersionId = ancestorVersion.isPresent() ? ancestorVersion.get().getMetadataId() : ObjectId.NULL;
                                ours = mergeIntoDiff.getNewObject().getMetadataId();
                                theirs = toMergeDiff.getNewObject().getMetadataId();
                                report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                            }
                        // if the metadata ids match, it means both branches have added the same
                        // tree, maybe with different content, but there is no need to do
                        // anything. The correct tree is already there and the merge can be run
                        // safely, so we do not add it neither as a conflicted change nor as an
                        // unconflicted one
                        } else {
                            report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                        }
                    }
                    break;
                case REMOVED:
                    // removed by both histories => no conflict and no need to do anything
                    break;
                case MODIFIED:
                    TYPE type = command(ResolveObjectType.class).setObjectId(toMergeDiff.getNewObject().objectId()).call();
                    if (TYPE.TREE.equals(type)) {
                        boolean conflict = !toMergeDiff.getNewObject().getMetadataId().equals(mergeIntoDiff.getNewObject().getMetadataId());
                        if (conflict) {
                            // In this case, we store the metadata id, not the element id
                            ancestorVersionId = ancestorVersion.isPresent() ? ancestorVersion.get().getMetadataId() : ObjectId.NULL;
                            ours = mergeIntoDiff.getNewObject().getMetadataId();
                            theirs = toMergeDiff.getNewObject().getMetadataId();
                            report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                        }
                    } else {
                        FeatureDiff toMergeFeatureDiff = command(DiffFeature.class).setOldVersion(Suppliers.ofInstance(toMergeDiff.getOldObject())).setNewVersion(Suppliers.ofInstance(toMergeDiff.getNewObject())).call();
                        FeatureDiff mergeIntoFeatureDiff = command(DiffFeature.class).setOldVersion(Suppliers.ofInstance(mergeIntoDiff.getOldObject())).setNewVersion(Suppliers.ofInstance(mergeIntoDiff.getNewObject())).call();
                        if (toMergeFeatureDiff.conflicts(mergeIntoFeatureDiff)) {
                            report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                        } else {
                            // try to perform automerge
                            if (!toMergeDiff.getNewObject().getMetadataId().equals(mergeIntoDiff.getNewObject().getMetadataId())) {
                                report.addConflict(new Conflict(path, ancestorVersionId, ours, theirs));
                            } else if (!toMergeFeatureDiff.equals(mergeIntoFeatureDiff)) {
                                Feature mergedFeature = command(MergeFeaturesOp.class).setFirstFeature(mergeIntoDiff.getNewObject()).setSecondFeature(toMergeDiff.getNewObject()).setAncestorFeature(mergeIntoDiff.getOldObject()).call();
                                RevFeature revFeature = RevFeatureBuilder.build(mergedFeature);
                                if (revFeature.getId().equals(toMergeDiff.newObjectId())) {
                                    // the resulting merged feature equals the feature to merge from
                                    // the branch, which means that it exists in the repo and there
                                    // is no need to add it
                                    report.addUnconflicted(toMergeDiff);
                                } else {
                                    RevFeatureType featureType = command(RevObjectParse.class).setObjectId(mergeIntoDiff.getNewObject().getMetadataId()).call(RevFeatureType.class).get();
                                    FeatureInfo merged = new FeatureInfo(mergedFeature, featureType, path);
                                    report.addMerged(merged);
                                }
                            }
                        }
                    }
                    break;
            }
        } else {
            // modified in the other branch under it.
            if (ChangeType.REMOVED.equals(toMergeDiff.changeType())) {
                TYPE type = command(ResolveObjectType.class).setObjectId(toMergeDiff.oldObjectId()).call();
                if (TYPE.TREE.equals(type)) {
                    String parentPath = toMergeDiff.oldPath();
                    Set<Entry<String, DiffEntry>> entries = mergeIntoDiffs.entrySet();
                    boolean conflict = false;
                    for (Entry<String, DiffEntry> entry : entries) {
                        if (entry.getKey().startsWith(parentPath)) {
                            if (!ChangeType.REMOVED.equals(entry.getValue().changeType())) {
                                RevCommit ancestorCommit = command(RevObjectParse.class).setRefSpec(ancestor.get().toString()).call(RevCommit.class).get();
                                RevTree ancestorTree = command(RevObjectParse.class).setObjectId(ancestorCommit.getTreeId()).call(RevTree.class).get();
                                Optional<NodeRef> ancestorVersion = command(FindTreeChild.class).setChildPath(path).setParent(ancestorTree).call();
                                ObjectId ancestorVersionId = ancestorVersion.isPresent() ? ancestorVersion.get().getNode().getObjectId() : ObjectId.NULL;
                                ObjectId theirs = toMergeDiff.getNewObject() == null ? ObjectId.NULL : toMergeDiff.getNewObject().objectId();
                                String oursRefSpec = mergeInto.getId().toString() + ":" + parentPath;
                                Optional<ObjectId> ours = command(RevParse.class).setRefSpec(oursRefSpec).call();
                                report.addConflict(new Conflict(path, ancestorVersionId, ours.get(), theirs));
                                conflict = true;
                                break;
                            }
                        }
                    }
                    if (!conflict) {
                        report.addUnconflicted(toMergeDiff);
                    }
                } else {
                    report.addUnconflicted(toMergeDiff);
                }
            } else {
                report.addUnconflicted(toMergeDiff);
            }
        }
    }
    return report;
}
Also used : FeatureInfo(org.locationtech.geogig.api.FeatureInfo) RevFeature(org.locationtech.geogig.api.RevFeature) DiffFeature(org.locationtech.geogig.api.plumbing.DiffFeature) Feature(org.opengis.feature.Feature) NodeRef(org.locationtech.geogig.api.NodeRef) FeatureDiff(org.locationtech.geogig.api.plumbing.diff.FeatureDiff) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry) Entry(java.util.Map.Entry) RevFeature(org.locationtech.geogig.api.RevFeature) TYPE(org.locationtech.geogig.api.RevObject.TYPE) RevFeatureType(org.locationtech.geogig.api.RevFeatureType) DiffEntry(org.locationtech.geogig.api.plumbing.diff.DiffEntry) RevCommit(org.locationtech.geogig.api.RevCommit) ObjectId(org.locationtech.geogig.api.ObjectId) DiffFeature(org.locationtech.geogig.api.plumbing.DiffFeature) FindTreeChild(org.locationtech.geogig.api.plumbing.FindTreeChild) FindCommonAncestor(org.locationtech.geogig.api.plumbing.FindCommonAncestor) RevObjectParse(org.locationtech.geogig.api.plumbing.RevObjectParse) RevTree(org.locationtech.geogig.api.RevTree)

Example 8 with FeatureInfo

use of org.locationtech.geogig.api.FeatureInfo in project GeoGig by boundlessgeo.

the class Patch method toString.

/**
     * 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();
}
Also used : TextSerializationFactory(org.locationtech.geogig.storage.text.TextSerializationFactory) RevObject(org.locationtech.geogig.api.RevObject) FeatureInfo(org.locationtech.geogig.api.FeatureInfo) RevFeature(org.locationtech.geogig.api.RevFeature) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException)

Example 9 with FeatureInfo

use of org.locationtech.geogig.api.FeatureInfo in project GeoGig by boundlessgeo.

the class PatchSerializer method write.

public static void write(Writer w, Patch patch) throws IOException {
    StringBuilder sb = new StringBuilder();
    List<RevFeatureType> featureTypes = patch.getFeatureTypes();
    for (RevFeatureType featureType : featureTypes) {
        ObjectWriter<RevObject> writer = factory.createObjectWriter(TYPE.FEATURETYPE);
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        writer.write(featureType, output);
        sb.append(output.toString());
        sb.append('\n');
    }
    TextSerializationFactory factory = new TextSerializationFactory();
    for (FeatureInfo feature : patch.getAddedFeatures()) {
        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 : patch.getRemovedFeatures()) {
        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 : patch.getModifiedFeatures()) {
        sb.append("M\t" + diff.getPath() + "\t" + diff.getOldFeatureType().getId().toString() + "\t" + diff.getNewFeatureType().getId().toString() + "\n");
        sb.append(diff.asText() + "\n");
    }
    for (FeatureTypeDiff diff : patch.getAlteredTrees()) {
        sb.append(diff.toString() + "\n");
    }
    w.write(sb.toString());
    w.flush();
}
Also used : TextSerializationFactory(org.locationtech.geogig.storage.text.TextSerializationFactory) RevObject(org.locationtech.geogig.api.RevObject) FeatureInfo(org.locationtech.geogig.api.FeatureInfo) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) RevFeature(org.locationtech.geogig.api.RevFeature) RevFeatureType(org.locationtech.geogig.api.RevFeatureType)

Aggregations

FeatureInfo (org.locationtech.geogig.api.FeatureInfo)9 RevFeature (org.locationtech.geogig.api.RevFeature)6 RevFeatureType (org.locationtech.geogig.api.RevFeatureType)5 NodeRef (org.locationtech.geogig.api.NodeRef)4 RevObject (org.locationtech.geogig.api.RevObject)4 Entry (java.util.Map.Entry)3 ObjectId (org.locationtech.geogig.api.ObjectId)3 RevObjectParse (org.locationtech.geogig.api.plumbing.RevObjectParse)3 PropertyDescriptor (org.opengis.feature.type.PropertyDescriptor)3 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 IOException (java.io.IOException)2 RevCommit (org.locationtech.geogig.api.RevCommit)2 FindCommonAncestor (org.locationtech.geogig.api.plumbing.FindCommonAncestor)2 DiffEntry (org.locationtech.geogig.api.plumbing.diff.DiffEntry)2 FeatureDiff (org.locationtech.geogig.api.plumbing.diff.FeatureDiff)2 DepthSearch (org.locationtech.geogig.repository.DepthSearch)2 TextSerializationFactory (org.locationtech.geogig.storage.text.TextSerializationFactory)2 Optional (com.google.common.base.Optional)1 Geometry (com.vividsolutions.jts.geom.Geometry)1 Collection (java.util.Collection)1