/* 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.porcelain; import org.locationtech.geogig.api.AbstractGeoGigOp; import org.locationtech.geogig.api.Node; import org.locationtech.geogig.api.NodeRef; import org.locationtech.geogig.api.ObjectId; import org.locationtech.geogig.api.RevFeature; import org.locationtech.geogig.api.RevFeatureType; import org.locationtech.geogig.api.RevObject; import org.locationtech.geogig.api.RevObject.TYPE; import org.locationtech.geogig.api.RevTree; import org.locationtech.geogig.api.plumbing.FindTreeChild; import org.locationtech.geogig.api.plumbing.ResolveTreeish; import org.locationtech.geogig.api.plumbing.RevObjectParse; import org.locationtech.geogig.di.CanRunDuringConflict; import org.locationtech.geogig.repository.SpatialOps; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.vividsolutions.jts.geom.Envelope; /** * Returns the NodeRef corresponding to a given refspec, if available. */ // The annotation is here to allow this being run from the 'conflicts' command. // Other than that, there is no reason for this to be restricted to non-conflicting scenarios @CanRunDuringConflict public class FeatureNodeRefFromRefspec extends AbstractGeoGigOp<Optional<NodeRef>> { private String ref; public FeatureNodeRefFromRefspec setRefspec(String ref) { this.ref = ref; return this; } private RevFeatureType getFeatureTypeFromRefSpec() { String featureTypeRef = NodeRef.parentPath(ref); String fullRef; if (featureTypeRef.contains(":")) { fullRef = featureTypeRef; } else { fullRef = "WORK_HEAD:" + featureTypeRef; } String treeRef = fullRef.split(":")[0]; String path = fullRef.split(":")[1]; ObjectId revTreeId = command(ResolveTreeish.class).setTreeish(treeRef).call().get(); RevTree revTree = command(RevObjectParse.class).setObjectId(revTreeId).call(RevTree.class) .get(); Optional<NodeRef> nodeRef = command(FindTreeChild.class).setParent(revTree) .setChildPath(path).setIndex(true).call(); Preconditions.checkArgument(nodeRef.isPresent(), "Invalid reference: %s", ref); RevFeatureType revFeatureType = command(RevObjectParse.class) .setObjectId(nodeRef.get().getMetadataId()).call(RevFeatureType.class).get(); return revFeatureType; } private Optional<RevFeature> getFeatureFromRefSpec() { Optional<RevObject> revObject = command(RevObjectParse.class).setRefSpec(ref).call( RevObject.class); if (!revObject.isPresent()) { // let's try to see if it is a feature in the working tree NodeRef.checkValidPath(ref); Optional<NodeRef> elementRef = command(FindTreeChild.class) .setParent(workingTree().getTree()).setChildPath(ref).setIndex(true).call(); Preconditions.checkArgument(elementRef.isPresent(), "Invalid reference: %s", ref); ObjectId id = elementRef.get().objectId(); revObject = command(RevObjectParse.class).setObjectId(id).call(RevObject.class); } if (revObject.isPresent()) { Preconditions.checkArgument(TYPE.FEATURE.equals(revObject.get().getType()), "%s does not resolve to a feature", ref); return Optional.of(RevFeature.class.cast(revObject.get())); } else { return Optional.absent(); } } @Override protected Optional<NodeRef> _call() { Optional<RevFeature> feature = getFeatureFromRefSpec(); if (feature.isPresent()) { RevFeatureType featureType = getFeatureTypeFromRefSpec(); RevFeature feat = feature.get(); Envelope bounds = SpatialOps.boundsOf(feat); Node node = Node.create(NodeRef.nodeFromPath(ref), feat.getId(), featureType.getId(), TYPE.FEATURE, bounds); return Optional.of(new NodeRef(node, NodeRef.parentPath(ref), featureType.getId())); } else { return Optional.absent(); /* * new NodeRef(Node.create("", ObjectId.NULL, ObjectId.NULL, TYPE.FEATURE), "", * ObjectId.NULL); */ } } }