You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2017/11/15 12:32:04 UTC
[1/2] tinkerpop git commit: TINKERPOP-1829 Made detachment
configurable in EventStrategy
Repository: tinkerpop
Updated Branches:
refs/heads/tp32 f3458ee7d -> ca2153238
TINKERPOP-1829 Made detachment configurable in EventStrategy
The default behavior is representative of how EventStrategy currently works so there is no breaking change here. In the interest of avoiding breaking changes, I didn't want to shift the API to make the change cleaner and thus created TINKERPOP-1831 for future consideration.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/a5f48d91
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/a5f48d91
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/a5f48d91
Branch: refs/heads/tp32
Commit: a5f48d91069d10fe8abdcbb0559315bae10ead5f
Parents: ac99e3c
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Nov 10 06:46:10 2017 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Nov 10 06:46:10 2017 -0500
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 12 +
.../upgrade/release-3.2.x-incubating.asciidoc | 10 +
.../process/traversal/step/filter/DropStep.java | 13 +-
.../process/traversal/step/map/AddEdgeStep.java | 4 +-
.../traversal/step/map/AddVertexStartStep.java | 4 +-
.../traversal/step/map/AddVertexStep.java | 4 +-
.../step/sideEffect/AddPropertyStep.java | 21 +-
.../strategy/decoration/EventStrategy.java | 68 ++
.../util/reference/ReferenceProperty.java | 2 +-
.../util/reference/ReferenceVertexProperty.java | 2 +-
.../decoration/EventStrategyProcessTest.java | 1046 +++++++++++++++++-
12 files changed, 1165 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index ffd9de5..3a2b5b5 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -23,6 +23,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
[[release-3-2-7]]
=== TinkerPop 3.2.7 (Release Date: NOT OFFICIALLY RELEASED YET)
+* Provided a method to configure detachment options with `EventStrategy`.
* Fixed an `ArrayOutOfBoundsException` in `hasId()` for the rare situation when the provided collection is empty.
* Bump to Netty 4.0.52
* `TraversalVertexProgram` `profile()` now accounts for worker iteration in `GraphComputer` OLAP.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/docs/src/reference/the-traversal.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 68773f5..a37a8bc 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -2853,6 +2853,18 @@ WARNING: `EventStrategy` is not meant for usage in tracking global mutations acr
words, a mutation in one JVM process is not raised as an event in a different JVM process. In addition, events are
not raised when mutations occur outside of the `Traversal` context.
+Another default configuration for `EventStrategy` revolves around the concept of "detachment". Graph elements are
+detached from the graph as copies when passed to referring mutation events. Therefore, when adding a new `Vertex` in
+TinkerGraph, the event will not contain a `TinkerVertex` but will instead include a `DetachedVertex`. This behavior
+can be modified with the `detach()` method on the `EventStrategy.Builder` which accepts the following inputs: `null`
+meaning no detachment and the return of the original element, `DetachedFactory` which is the same as the default
+behavior, and `ReferenceFactory` which will return "reference" elements only with no properties.
+
+IMPORTANT: If setting the `detach()` configuration to `null`, be aware that transactional graphs will likely create a
+new transaction immediately following the `commit()` that raises the events. The graph elements raised in the events
+may also not behave as "snapshots" at the time of their creation as they are "live" references to actual database
+elements.
+
=== PartitionStrategy
image::partition-graph.png[width=325]
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
index c09f9c6..1589069 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -29,6 +29,16 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
Please see the link:https://github.com/apache/tinkerpop/blob/3.2.7/CHANGELOG.asciidoc#release-3-2-7[changelog] for a complete list of all the modifications that are part of this release.
+==== EventStrategy Detachment
+
+`EventStrategy` forced detachment of mutated elements prior to raising them in events. While this was a desired
+outcome, it may not have always fit every use case. For example, a user may have wanted a reference element or the
+actual element itself. As a result, `EventStrategy` has changed to allow it to be constructed with a `detach()`
+option, where it is possible to specify any of the following: `null` for no detachment, `DetachedFactory` for the
+original behavior, and `ReferenceFactory` for detachment that returns reference elements.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1829[TINKERPOP-1829]
+
==== Embedded Remote Connection
As Gremlin Language Variants (GLVs) expand their usage and use of `withRemote()` becomes more common, the need to mock
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DropStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DropStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DropStep.java
index 87790eb..cd95e48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DropStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DropStep.java
@@ -24,6 +24,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Property;
@@ -49,13 +50,14 @@ public final class DropStep<S> extends FilterStep<S> implements Mutating<Event>
if (s instanceof Element) {
final Element toRemove = (Element) s;
if (callbackRegistry != null) {
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
final Event removeEvent;
if (s instanceof Vertex)
- removeEvent = new Event.VertexRemovedEvent(DetachedFactory.detach((Vertex) s, true));
+ removeEvent = new Event.VertexRemovedEvent(eventStrategy.detach((Vertex) s));
else if (s instanceof Edge)
- removeEvent = new Event.EdgeRemovedEvent(DetachedFactory.detach((Edge) s, true));
+ removeEvent = new Event.EdgeRemovedEvent(eventStrategy.detach((Edge) s));
else if (s instanceof VertexProperty)
- removeEvent = new Event.VertexPropertyRemovedEvent(DetachedFactory.detach((VertexProperty) s, true));
+ removeEvent = new Event.VertexPropertyRemovedEvent(eventStrategy.detach((VertexProperty) s));
else
throw new IllegalStateException("The incoming object is not removable: " + s);
@@ -66,11 +68,12 @@ public final class DropStep<S> extends FilterStep<S> implements Mutating<Event>
} else if (s instanceof Property) {
final Property toRemove = (Property) s;
if (callbackRegistry != null) {
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
final Event.ElementPropertyEvent removeEvent;
if (toRemove.element() instanceof Edge)
- removeEvent = new Event.EdgePropertyRemovedEvent((Edge) toRemove.element(), DetachedFactory.detach(toRemove));
+ removeEvent = new Event.EdgePropertyRemovedEvent(eventStrategy.detach((Edge) toRemove.element()), eventStrategy.detach(toRemove));
else if (toRemove.element() instanceof VertexProperty)
- removeEvent = new Event.VertexPropertyPropertyRemovedEvent((VertexProperty) toRemove.element(), DetachedFactory.detach(toRemove));
+ removeEvent = new Event.VertexPropertyPropertyRemovedEvent(eventStrategy.detach((VertexProperty) toRemove.element()), eventStrategy.detach(toRemove));
else
throw new IllegalStateException("The incoming object is not removable: " + s);
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
index efe5906..b5e52c5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -29,6 +29,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -104,7 +105,8 @@ public final class AddEdgeStep<S> extends MapStep<S, Edge>
final Edge edge = fromVertex.addEdge(edgeLabel, toVertex, this.parameters.getKeyValues(traverser, TO, FROM, T.label));
if (callbackRegistry != null) {
- final Event.EdgeAddedEvent vae = new Event.EdgeAddedEvent(DetachedFactory.detach(edge, true));
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
+ final Event.EdgeAddedEvent vae = new Event.EdgeAddedEvent(eventStrategy.detach(edge));
callbackRegistry.getCallbacks().forEach(c -> c.accept(vae));
}
return edge;
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
index 7de8839..7eb018b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java
@@ -31,6 +31,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
import org.apache.tinkerpop.gremlin.structure.T;
@@ -84,7 +85,8 @@ public final class AddVertexStartStep extends AbstractStep<Vertex, Vertex>
final TraverserGenerator generator = this.getTraversal().getTraverserGenerator();
final Vertex vertex = this.getTraversal().getGraph().get().addVertex(this.parameters.getKeyValues(generator.generate(false, (Step) this, 1L)));
if (this.callbackRegistry != null) {
- final Event.VertexAddedEvent vae = new Event.VertexAddedEvent(DetachedFactory.detach(vertex, true));
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
+ final Event.VertexAddedEvent vae = new Event.VertexAddedEvent(eventStrategy.detach(vertex));
this.callbackRegistry.getCallbacks().forEach(c -> c.accept(vae));
}
return generator.generate(vertex, this, 1L);
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index c35fa80..521c5ac 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
@@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -76,7 +77,8 @@ public final class AddVertexStep<S> extends MapStep<S, Vertex>
protected Vertex map(final Traverser.Admin<S> traverser) {
final Vertex vertex = this.getTraversal().getGraph().get().addVertex(this.parameters.getKeyValues(traverser));
if (this.callbackRegistry != null) {
- final Event.VertexAddedEvent vae = new Event.VertexAddedEvent(DetachedFactory.detach(vertex, true));
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
+ final Event.VertexAddedEvent vae = new Event.VertexAddedEvent(eventStrategy.detach(vertex));
this.callbackRegistry.getCallbacks().forEach(c -> c.accept(vae));
}
return vertex;
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
index 3de8932..7509f86 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java
@@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Element;
@@ -91,26 +92,26 @@ public final class AddPropertyStep<S extends Element> extends SideEffectStep<S>
final Element element = traverser.get();
-
if (this.callbackRegistry != null) {
+ final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
final Property currentProperty = traverser.get().property(key);
final boolean newProperty = element instanceof Vertex ? currentProperty == VertexProperty.empty() : currentProperty == Property.empty();
final Event.ElementPropertyChangedEvent evt;
if (element instanceof Vertex)
- evt = new Event.VertexPropertyChangedEvent(DetachedFactory.detach((Vertex) element, true),
+ evt = new Event.VertexPropertyChangedEvent(eventStrategy.detach((Vertex) element),
newProperty ?
- new DetachedVertexProperty(null, key, null, null) :
- DetachedFactory.detach((VertexProperty) currentProperty, true), value, vertexPropertyKeyValues);
+ eventStrategy.empty(element, key) :
+ eventStrategy.detach((VertexProperty) currentProperty), value, vertexPropertyKeyValues);
else if (element instanceof Edge)
- evt = new Event.EdgePropertyChangedEvent(DetachedFactory.detach((Edge) element, true),
+ evt = new Event.EdgePropertyChangedEvent(eventStrategy.detach((Edge) element),
newProperty ?
- new DetachedProperty(key, null) :
- DetachedFactory.detach(currentProperty), value);
+ eventStrategy.empty(element, key) :
+ eventStrategy.detach(currentProperty), value);
else if (element instanceof VertexProperty)
- evt = new Event.VertexPropertyPropertyChangedEvent(DetachedFactory.detach((VertexProperty) element, true),
+ evt = new Event.VertexPropertyPropertyChangedEvent(eventStrategy.detach((VertexProperty) element),
newProperty ?
- new DetachedProperty(key, null) :
- DetachedFactory.detach(currentProperty), value);
+ eventStrategy.empty(element, key) :
+ eventStrategy.detach(currentProperty), value);
else
throw new IllegalStateException(String.format("The incoming object cannot be processed by change eventing in %s: %s", AddPropertyStep.class.getName(), element));
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
index 30b48fa..b4824c8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
@@ -26,8 +26,19 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventCallb
import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.MutationListener;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceProperty;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
import java.io.Serializable;
import java.util.ArrayDeque;
@@ -46,10 +57,53 @@ import java.util.List;
*/
public final class EventStrategy extends AbstractTraversalStrategy<TraversalStrategy.DecorationStrategy> implements TraversalStrategy.DecorationStrategy {
private final EventQueue eventQueue;
+ private final Class<?> detachmentFactory;
private EventStrategy(final Builder builder) {
this.eventQueue = builder.eventQueue;
this.eventQueue.setListeners(builder.listeners);
+ this.detachmentFactory = builder.detachmentFactory;
+ }
+
+ public Class<?> getDetachmentFactory() {
+ return this.detachmentFactory;
+ }
+
+ /**
+ * Applies the appropriate detach operation to elements that will be raised in mutation events.
+ */
+ public <R> R detach(final R attached) {
+ if (null == detachmentFactory)
+ return attached;
+ else if (detachmentFactory.equals(DetachedFactory.class))
+ return DetachedFactory.detach(attached, true);
+ else if (detachmentFactory.equals(ReferenceFactory.class))
+ return ReferenceFactory.detach(attached);
+ else
+ throw new IllegalStateException("Unknown detachment option using " + detachmentFactory.getSimpleName());
+ }
+
+ /**
+ * For newly created properties that do not yet exist, an empty {@link Property} is required that just contains
+ * a key as a reference.
+ */
+ public <R extends Property> R empty(final Element element, final String key) {
+ // currently the "no detachment" model simply returns a Detached value to maintain consistency with the
+ // original API that already existed (where returning "Detached" was the only option). This could probably
+ // change in the future to use an "empty" property or perhaps the "change" event API could change all together
+ // and have a different return.
+ if (null == detachmentFactory || detachmentFactory.equals(DetachedFactory.class)) {
+ if (element instanceof Vertex)
+ return (R) new DetachedVertexProperty(null, key, null, null);
+ else
+ return (R) new DetachedProperty(key, null);
+ } else if (detachmentFactory.equals(ReferenceFactory.class)) {
+ if (element instanceof Vertex)
+ return (R) new ReferenceVertexProperty(new DetachedVertexProperty(null, key, null, null));
+ else
+ return (R) new ReferenceProperty(new DetachedProperty(key, null));
+ } else
+ throw new IllegalStateException("Unknown empty detachment option using " + detachmentFactory.getSimpleName());
}
@Override
@@ -78,6 +132,7 @@ public final class EventStrategy extends AbstractTraversalStrategy<TraversalStra
public final static class Builder {
private final List<MutationListener> listeners = new ArrayList<>();
private EventQueue eventQueue = new DefaultEventQueue();
+ private Class<?> detachmentFactory = DetachedFactory.class;
Builder() {}
@@ -91,6 +146,19 @@ public final class EventStrategy extends AbstractTraversalStrategy<TraversalStra
return this;
}
+ /**
+ * Configures the method of detachment for element provided in mutation callback events. If configured with
+ * {@code null} for no detachment with a transactional graph, be aware that accessing the evented elements
+ * after {@code commit()} will likely open new transactions.
+ *
+ * @param factoryClass must be either {@code null} (for no detachment), {@link ReferenceFactory} for elements
+ * with no properties or {@link DetachedFactory} for elements with properties.
+ */
+ public Builder detach(final Class<?> factoryClass) {
+ detachmentFactory = factoryClass;
+ return this;
+ }
+
public EventStrategy create() {
return new EventStrategy(this);
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceProperty.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceProperty.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceProperty.java
index dc86518..074f863 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceProperty.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceProperty.java
@@ -47,7 +47,7 @@ public class ReferenceProperty<V> implements Attachable<Property<V>>, Serializab
}
public ReferenceProperty(final Property<V> property) {
- this.element = ReferenceFactory.detach(property.element());
+ this.element = null == property.element() ? null : ReferenceFactory.detach(property.element());
this.key = property.key();
this.value = property.value();
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceVertexProperty.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceVertexProperty.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceVertexProperty.java
index e607ebb..c8fdd5c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceVertexProperty.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/reference/ReferenceVertexProperty.java
@@ -42,7 +42,7 @@ public class ReferenceVertexProperty<V> extends ReferenceElement<VertexProperty<
public ReferenceVertexProperty(final VertexProperty<V> vertexProperty) {
super(vertexProperty);
- this.vertex = ReferenceFactory.detach(vertexProperty.element());
+ this.vertex = null == vertexProperty.element() ? null : ReferenceFactory.detach(vertexProperty.element());
this.value = vertexProperty.value();
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a5f48d91/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
index 12a3e0a..e7a392c 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
@@ -28,6 +28,13 @@ import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Property;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceEdge;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import org.junit.Test;
@@ -36,9 +43,11 @@ import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
/**
@@ -544,6 +553,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyPropertyRemoved(final VertexProperty element, final Property property) {
+ assertThat(element, instanceOf(DetachedVertexProperty.class));
assertEquals(label, element.label());
assertEquals(value, element.value());
assertEquals("dah", property.value());
@@ -582,6 +592,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(DetachedVertexProperty.class));
assertEquals(label, element.label());
assertEquals(value, element.value());
assertEquals("dah", oldValue.value());
@@ -620,6 +631,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(DetachedVertexProperty.class));
assertEquals(label, element.label());
assertEquals(value, element.value());
assertEquals(null, oldValue.value());
@@ -658,6 +670,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void edgePropertyRemoved(final Edge element, final Property property) {
+ assertThat(element, instanceOf(DetachedEdge.class));
assertEquals(label, element.label());
assertEquals(inId, element.inVertex().id());
assertEquals(outId, element.outVertex().id());
@@ -696,6 +709,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(DetachedEdge.class));
assertEquals(label, element.label());
assertEquals(inId, element.inVertex().id());
assertEquals(outId, element.outVertex().id());
@@ -734,6 +748,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(DetachedEdge.class));
assertEquals(label, element.label());
assertEquals(inId, element.inVertex().id());
assertEquals(outId, element.outVertex().id());
@@ -772,6 +787,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void edgeRemoved(final Edge element) {
+ assertThat(element, instanceOf(DetachedEdge.class));
assertEquals(label, element.label());
assertEquals(inId, element.inVertex().id());
assertEquals(outId, element.outVertex().id());
@@ -803,6 +819,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void edgeAdded(final Edge element) {
+ assertThat(element, instanceOf(DetachedEdge.class));
assertEquals("self", element.label());
assertEquals(id, element.inVertex().id());
assertEquals(id, element.outVertex().id());
@@ -838,6 +855,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyRemoved(final VertexProperty element) {
+ assertThat(element, instanceOf(DetachedVertexProperty.class));
assertEquals(label, element.label());
assertEquals(value, element.value());
triggered.set(true);
@@ -869,10 +887,9 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
v.property("to-change", "blah");
final MutationListener listener = new AbstractMutationListener() {
-
-
@Override
public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(DetachedVertex.class));
assertEquals(label, element.label());
assertEquals(id, element.id());
assertEquals("to-change", oldValue.key());
@@ -908,6 +925,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(DetachedVertex.class));
assertEquals(label, element.label());
assertEquals(id, element.id());
assertEquals("new", oldValue.key());
@@ -943,6 +961,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexPropertyChanged(final Vertex element, final Property oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(DetachedVertex.class));
assertEquals(label, element.label());
assertEquals(id, element.id());
assertEquals("new", oldValue.key());
@@ -977,6 +996,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexRemoved(final Vertex element) {
+ assertThat(element, instanceOf(DetachedVertex.class));
assertEquals(id, element.id());
assertEquals(label, element.label());
triggered.set(true);
@@ -1005,6 +1025,7 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
final MutationListener listener = new AbstractMutationListener() {
@Override
public void vertexAdded(final Vertex element) {
+ assertThat(element, instanceOf(DetachedVertex.class));
assertEquals("thing", element.label());
assertEquals("there", element.value("here"));
triggered.set(true);
@@ -1025,6 +1046,1027 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
assertThat(triggered.get(), is(true));
}
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldReferencePropertyOfVertexPropertyWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ final Property p = vp.property("to-drop", "dah");
+ vp.property("not-dropped", "yay!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyRemoved(final VertexProperty element, final Property property) {
+ assertThat(element, instanceOf(ReferenceVertexProperty.class));
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ assertEquals("dah", property.value());
+ assertEquals("to-drop", property.key());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").properties("to-drop").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(1, IteratorUtils.count(g.V(v).properties().properties()));
+ assertEquals("yay!", g.V(vp.element()).properties("xxx").values("not-dropped").next());
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldReferencePropertyOfVertexPropertyWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ vp.property("to-change", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(ReferenceVertexProperty.class));
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ assertEquals("dah", oldValue.value());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("bah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").property("to-change","bah").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(1, IteratorUtils.count(g.V(v).properties().properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldReferencePropertyOfVertexPropertyWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ vp.property("to-change", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(ReferenceVertexProperty.class));
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ assertEquals(null, oldValue.value());
+ assertEquals("new", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").property("new","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(2, IteratorUtils.count(g.V(v).properties().properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldReferencePropertyOfEdgeWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v, "not-dropped", "yay!");
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-drop", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyRemoved(final Edge element, final Property property) {
+ assertThat(element, instanceOf(ReferenceEdge.class));
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals("dah", property.value());
+ assertEquals("to-drop", property.key());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).properties("to-drop").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.E(e).properties()));
+ assertEquals("yay!", e.value("not-dropped"));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldReferencePropertyOfEdgeWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v);
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-change", "no!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(ReferenceEdge.class));
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals("no!", oldValue.value());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).property("to-change","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.E(e).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldReferencePropertyOfEdgeWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v);
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-change", "no!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertThat(element, instanceOf(ReferenceEdge.class));
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals(null, oldValue.value());
+ assertEquals("new", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).property("new","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.E(e).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldReferenceEdgeWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v, "dropped", "yay!");
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgeRemoved(final Edge element) {
+ assertThat(element, instanceOf(ReferenceEdge.class));
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).drop().iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 0);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldReferenceEdgeWhenAdded() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Object id = v.id();
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgeAdded(final Edge element) {
+ assertThat(element, instanceOf(ReferenceEdge.class));
+ assertEquals("self", element.label());
+ assertEquals(id, element.inVertex().id());
+ assertEquals(id, element.outVertex().id());
+ assertThat(element.properties().hasNext(), is(false));
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).as("a").addE("self").property("here", "there").from("a").to("a").iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 1);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldReferenceVertexPropertyWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("to-remove","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ final VertexProperty vpToKeep = v.property("to-keep","dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyRemoved(final VertexProperty element) {
+ assertThat(element, instanceOf(ReferenceVertexProperty.class));
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("to-remove").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(vpToKeep.value(), g.V(v).values("to-keep").next());
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldReferenceVertexPropertyWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("to-change", "blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+
+
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(ReferenceVertex.class));
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("blah", oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "to-change", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldRefereceVertexPropertyWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("old","blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(ReferenceVertex.class));
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("new", oldValue.key());
+ assertEquals(null, oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "new", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldReferenceVertexPropertyWhenNewDeprecated() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("old","blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final Property oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertThat(element, instanceOf(ReferenceVertex.class));
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("new", oldValue.key());
+ assertEquals(null, oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "new", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldReferenceVertexWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexRemoved(final Vertex element) {
+ assertThat(element, instanceOf(ReferenceVertex.class));
+ assertEquals(id, element.id());
+ assertEquals(label, element.label());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).drop().iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 0, 0);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldReferenceVertexWhenAdded() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexAdded(final Vertex element) {
+ assertThat(element, instanceOf(ReferenceVertex.class));
+ assertEquals("thing", element.label());
+ assertThat(element.properties("here").hasNext(), is(false));
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.addV("thing").property("here", "there").iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 0);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldUseActualPropertyOfVertexPropertyWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ final Property p = vp.property("to-drop", "dah");
+ vp.property("not-dropped", "yay!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyRemoved(final VertexProperty element, final Property property) {
+ assertEquals(vp, element);
+ assertEquals(p, property);
+ assertEquals("dah", property.value());
+ assertEquals("to-drop", property.key());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").properties("to-drop").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(1, IteratorUtils.count(g.V(v).properties().properties()));
+ assertEquals("yay!", g.V(vp.element()).properties("xxx").values("not-dropped").next());
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldUseActualPropertyOfVertexPropertyWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ vp.property("to-change", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertEquals(vp, element);
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ assertEquals("dah", oldValue.value());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("bah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").property("to-change","bah").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(1, IteratorUtils.count(g.V(v).properties().properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
+ public void shouldUseActualPropertyOfVertexPropertyWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("xxx","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ vp.property("to-change", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyPropertyChanged(final VertexProperty element, final Property oldValue, final Object setValue) {
+ assertEquals(vp, element);
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ assertEquals(null, oldValue.value());
+ assertEquals("new", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("xxx").property("new","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(2, IteratorUtils.count(g.V(v).properties().properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldUseActualPropertyOfEdgeWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v, "not-dropped", "yay!");
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-drop", "dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyRemoved(final Edge element, final Property property) {
+ assertEquals(e, element);
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals("dah", property.value());
+ assertEquals("to-drop", property.key());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).properties("to-drop").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.E(e).properties()));
+ assertEquals("yay!", e.value("not-dropped"));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldUseActualPropertyOfEdgeWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v);
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-change", "no!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertEquals(e, element);
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals("no!", oldValue.value());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).property("to-change","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.E(e).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldUseActualPropertyOfEdgeWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v);
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+ e.property("to-change", "no!");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgePropertyChanged(final Edge element, final Property oldValue, final Object setValue) {
+ assertEquals(e, element);
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ assertEquals(null, oldValue.value());
+ assertEquals("new", oldValue.key());
+ assertEquals("yay!", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).property("new","yay!").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.E(e).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldUseActualEdgeWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Edge e = v.addEdge("self", v, "dropped", "yay!");
+ final String label = e.label();
+ final Object inId = v.id();
+ final Object outId = v.id();
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgeRemoved(final Edge element) {
+ assertEquals(e, element);
+ assertEquals(label, element.label());
+ assertEquals(inId, element.inVertex().id());
+ assertEquals(outId, element.outVertex().id());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.E(e).drop().iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 0);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.SIMPLE)
+ public void shouldUseActualEdgeWhenAdded() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final Object id = v.id();
+
+ final AtomicReference<Edge> eventedEdge = new AtomicReference<>();
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void edgeAdded(final Edge element) {
+ eventedEdge.set(element);
+ assertEquals("self", element.label());
+ assertEquals(id, element.inVertex().id());
+ assertEquals(id, element.outVertex().id());
+ assertThat(element.properties().hasNext(), is(false));
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ final Edge e = gts.V(v).as("a").addE("self").property("here", "there").from("a").to("a").next();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 1);
+ assertThat(triggered.get(), is(true));
+ assertEquals(e, eventedEdge.get());
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexPropertyWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final VertexProperty vp = v.property("to-remove","blah");
+ final String label = vp.label();
+ final Object value = vp.value();
+ final VertexProperty vpToKeep = v.property("to-keep","dah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyRemoved(final VertexProperty element) {
+ assertEquals(vp, element);
+ assertEquals(label, element.label());
+ assertEquals(value, element.value());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).properties("to-remove").drop().iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertEquals(vpToKeep.value(), g.V(v).values("to-keep").next());
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexPropertyWhenChanged() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("to-change", "blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertEquals(v, element);
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("to-change", oldValue.key());
+ assertEquals("blah", oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "to-change", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(1, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexPropertyWhenNew() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("old","blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final VertexProperty oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertEquals(v, element);
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("new", oldValue.key());
+ assertEquals(null, oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "new", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexPropertyWhenNewDeprecated() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+ v.property("old","blah");
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexPropertyChanged(final Vertex element, final Property oldValue, final Object setValue, final Object... vertexPropertyKeyValues) {
+ assertEquals(v, element);
+ assertEquals(label, element.label());
+ assertEquals(id, element.id());
+ assertEquals("new", oldValue.key());
+ assertEquals(null, oldValue.value());
+ assertEquals("dah", setValue);
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).property(VertexProperty.Cardinality.single, "new", "dah").iterate();
+ tryCommit(graph);
+
+ assertEquals(2, IteratorUtils.count(g.V(v).properties()));
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexWhenRemoved() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+ final Vertex v = graph.addVertex();
+ final String label = v.label();
+ final Object id = v.id();
+
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexRemoved(final Vertex element) {
+ assertEquals(v, element);
+ assertEquals(id, element.id());
+ assertEquals(label, element.label());
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ gts.V(v).drop().iterate();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 0, 0);
+ assertThat(triggered.get(), is(true));
+ }
+
+ @Test
+ @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+ public void shouldUseActualVertexWhenAdded() {
+ final AtomicBoolean triggered = new AtomicBoolean(false);
+
+ final AtomicReference<Vertex> eventedVertex = new AtomicReference<>();
+ final MutationListener listener = new AbstractMutationListener() {
+ @Override
+ public void vertexAdded(final Vertex element) {
+ eventedVertex.set(element);
+ assertEquals("thing", element.label());
+ assertThat(element.properties("here").hasNext(), is(false));
+ triggered.set(true);
+ }
+ };
+ final EventStrategy.Builder builder = EventStrategy.build().addListener(listener).detach(ReferenceFactory.class);
+
+ if (graph.features().graph().supportsTransactions())
+ builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+ final EventStrategy eventStrategy = builder.create();
+ final GraphTraversalSource gts = create(eventStrategy);
+
+ final Vertex v = gts.addV("thing").property("here", "there").next();
+ tryCommit(graph);
+
+ assertVertexEdgeCounts(graph, 1, 0);
+ assertThat(triggered.get(), is(true));
+ assertEquals(v, eventedVertex.get());
+ }
+
private GraphTraversalSource create(final EventStrategy strategy) {
return graphProvider.traversal(graph, strategy);
}
[2/2] tinkerpop git commit: Merge branch 'TINKERPOP-1829' into tp32
Posted by sp...@apache.org.
Merge branch 'TINKERPOP-1829' into tp32
Conflicts:
CHANGELOG.asciidoc
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/ca215323
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/ca215323
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/ca215323
Branch: refs/heads/tp32
Commit: ca2153238bb4d62789ab33215890c15c1fdead23
Parents: f3458ee a5f48d9
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Wed Nov 15 07:31:11 2017 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Nov 15 07:31:11 2017 -0500
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 12 +
.../upgrade/release-3.2.x-incubating.asciidoc | 10 +
.../process/traversal/step/filter/DropStep.java | 13 +-
.../process/traversal/step/map/AddEdgeStep.java | 4 +-
.../traversal/step/map/AddVertexStartStep.java | 4 +-
.../traversal/step/map/AddVertexStep.java | 4 +-
.../step/sideEffect/AddPropertyStep.java | 21 +-
.../strategy/decoration/EventStrategy.java | 68 ++
.../util/reference/ReferenceProperty.java | 2 +-
.../util/reference/ReferenceVertexProperty.java | 2 +-
.../decoration/EventStrategyProcessTest.java | 1046 +++++++++++++++++-
12 files changed, 1165 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ca215323/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index cd5dc38,3a2b5b5..df00fa5
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -23,7 -23,7 +23,8 @@@ image::https://raw.githubusercontent.co
[[release-3-2-7]]
=== TinkerPop 3.2.7 (Release Date: NOT OFFICIALLY RELEASED YET)
+ * Provided a method to configure detachment options with `EventStrategy`.
+* Fixed a race condition in `TinkerIndex`.
* Fixed an `ArrayOutOfBoundsException` in `hasId()` for the rare situation when the provided collection is empty.
* Bump to Netty 4.0.52
* `TraversalVertexProgram` `profile()` now accounts for worker iteration in `GraphComputer` OLAP.