/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tinkerpop.gremlin.process.traversal.util; import org.apache.tinkerpop.gremlin.process.traversal.Operator; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BinaryOperator; import java.util.function.Supplier; import java.util.function.UnaryOperator; /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class DefaultTraversalSideEffects implements TraversalSideEffects { protected Set<String> keys = new HashSet<>(); protected Map<String, Object> objectMap = new HashMap<>(); protected Map<String, Supplier> supplierMap = new HashMap<>(); protected Map<String, BinaryOperator> reducerMap = new HashMap<>(); protected UnaryOperator sackSplitOperator = null; protected BinaryOperator sackMergeOperator = null; protected Supplier sackInitialValue = null; public DefaultTraversalSideEffects() { } /** * {@inheritDoc} */ @Override public boolean exists(final String key) { return this.keys.contains(key); } /** * {@inheritDoc} */ @Override public <V> V get(final String key) throws IllegalArgumentException { final V value = (V) this.objectMap.get(key); if (null != value) return value; else { final V v = this.<V>getSupplier(key).get(); this.objectMap.put(key, v); return v; } } /** * {@inheritDoc} */ @Override public void set(final String key, final Object value) throws IllegalArgumentException { SideEffectHelper.validateSideEffectValue(value); if (!this.keys.contains(key)) throw TraversalSideEffects.Exceptions.sideEffectKeyDoesNotExist(key); this.objectMap.put(key, value); } /** * {@inheritDoc} */ @Override public void add(final String key, final Object value) throws IllegalArgumentException { SideEffectHelper.validateSideEffectValue(value); this.set(key, this.getReducer(key).apply(this.get(key), value)); } /** * {@inheritDoc} */ @Override public <V> void register(final String key, final Supplier<V> initialValue, final BinaryOperator<V> reducer) { SideEffectHelper.validateSideEffectKey(key); this.keys.add(key); //this.objectMap.remove(key); if (null != initialValue) this.supplierMap.put(key, initialValue); if (null != reducer) this.reducerMap.put(key, reducer); } /** * {@inheritDoc} */ @Override public <V> void registerIfAbsent(final String key, final Supplier<V> initialValue, final BinaryOperator<V> reducer) { SideEffectHelper.validateSideEffectKey(key); this.keys.add(key); //this.objectMap.remove(key); if (null == this.supplierMap.get(key) && null != initialValue) { this.supplierMap.put(key, initialValue); } if (null == this.reducerMap.get(key) && null != reducer) { this.reducerMap.put(key, reducer); } } /** * {@inheritDoc} */ @Override public <V> BinaryOperator<V> getReducer(final String key) throws IllegalArgumentException { if (!this.keys.contains(key)) throw TraversalSideEffects.Exceptions.sideEffectKeyDoesNotExist(key); return this.reducerMap.getOrDefault(key, Operator.assign); } /** * {@inheritDoc} */ @Override public <V> Supplier<V> getSupplier(final String key) throws IllegalArgumentException { final Supplier<V> supplier = this.supplierMap.get(key); if (null == supplier) throw TraversalSideEffects.Exceptions.sideEffectKeyDoesNotExist(key); return supplier; } /** * {@inheritDoc} */ @Override public <S> void setSack(final Supplier<S> initialValue, final UnaryOperator<S> splitOperator, final BinaryOperator<S> mergeOperator) { this.sackInitialValue = initialValue; this.sackSplitOperator = splitOperator; this.sackMergeOperator = mergeOperator; } /** * {@inheritDoc} */ @Override public <S> Supplier<S> getSackInitialValue() { return this.sackInitialValue; } /** * {@inheritDoc} */ @Override public <S> UnaryOperator<S> getSackSplitter() { return this.sackSplitOperator; } /** * {@inheritDoc} */ @Override public <S> BinaryOperator<S> getSackMerger() { return this.sackMergeOperator; } /** * {@inheritDoc} */ @Override public void remove(final String key) { this.objectMap.remove(key); this.supplierMap.remove(key); this.reducerMap.remove(key); this.keys.remove(key); } /** * {@inheritDoc} */ @Override public Set<String> keys() { return Collections.unmodifiableSet(this.keys); } /** * {@inheritDoc} */ @Override public void mergeInto(final TraversalSideEffects sideEffects) { for (final String key : this.keys) { sideEffects.registerIfAbsent(key, this.supplierMap.get(key), this.reducerMap.get(key)); if (this.objectMap.containsKey(key)) sideEffects.set(key, this.objectMap.get(key)); } } /** * {@inheritDoc} */ @Override public String toString() { return StringFactory.traversalSideEffectsString(this); } /** * {@inheritDoc} */ @Override @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") public DefaultTraversalSideEffects clone() { try { final DefaultTraversalSideEffects sideEffects = (DefaultTraversalSideEffects) super.clone(); sideEffects.keys = new HashSet<>(this.keys); sideEffects.objectMap = new HashMap<>(this.objectMap); sideEffects.supplierMap = new HashMap<>(this.supplierMap); sideEffects.reducerMap = new HashMap<>(this.reducerMap); return sideEffects; } catch (final CloneNotSupportedException e) { throw new IllegalStateException(e.getMessage(), e); } } ////////// /** * {@inheritDoc} */ @Deprecated @Override public void registerSupplier(final String key, final Supplier supplier) { this.register(key, supplier, null); } /** * {@inheritDoc} */ @Deprecated @Override public void registerSupplierIfAbsent(final String key, final Supplier supplier) { this.registerIfAbsent(key, supplier, null); } /** * {@inheritDoc} */ @Override @Deprecated public <V> Optional<Supplier<V>> getRegisteredSupplier(final String key) { return Optional.ofNullable(this.supplierMap.get(key)); } /** * {@inheritDoc} */ @Override @Deprecated public <V> V getOrCreate(final String key, final Supplier<V> orCreate) { final V value = this.exists(key) ? this.get(key) : null; if (null != value) return value; else { final V newValue = orCreate.get(); this.objectMap.put(key, newValue); return newValue; } } }