/*
*
* * 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.usergrid.persistence.graph.serialization.impl.shard;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.usergrid.persistence.core.scope.ApplicationScope;
import org.apache.usergrid.persistence.graph.Edge;
import org.apache.usergrid.persistence.graph.MarkedEdge;
import org.apache.usergrid.persistence.graph.SearchByEdgeType;
import org.apache.usergrid.persistence.graph.SearchByIdType;
import org.apache.usergrid.persistence.graph.impl.SimpleSearchByEdge;
import org.apache.usergrid.persistence.graph.impl.SimpleSearchByEdgeType;
import org.apache.usergrid.persistence.graph.impl.SimpleSearchByIdType;
import org.apache.usergrid.persistence.model.entity.Id;
import com.google.common.base.Optional;
import com.netflix.astyanax.MutationBatch;
/**
* A bean to define directed edge meta data. This is used to encapsulate the meta data around a source or target node,
* and the types used for grouping them.
*/
public abstract class DirectedEdgeMeta {
protected final NodeMeta[] nodes;
protected final String[] types;
private DirectedEdgeMeta( NodeMeta[] nodes, String[] types ) {
this.nodes = nodes;
this.types = types;
}
public NodeMeta[] getNodes() {
return nodes;
}
public String[] getTypes() {
return types;
}
/**
* Inner class to represent node meta dat
*/
public static class NodeMeta {
private final Id id;
private final NodeType nodeType;
public NodeMeta( final Id id, final NodeType nodeType ) {
this.id = id;
this.nodeType = nodeType;
}
public Id getId() {
return id;
}
public NodeType getNodeType() {
return nodeType;
}
@Override
public boolean equals( final Object o ) {
if ( this == o ) {
return true;
}
if ( !( o instanceof NodeMeta ) ) {
return false;
}
final NodeMeta nodeMeta = ( NodeMeta ) o;
if ( !id.equals( nodeMeta.id ) ) {
return false;
}
if ( nodeType != nodeMeta.nodeType ) {
return false;
}
return true;
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(id)
.append(nodeType)
.toHashCode();
}
}
@Override
public boolean equals( final Object o ) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final DirectedEdgeMeta that = ( DirectedEdgeMeta ) o;
if ( !Arrays.equals( nodes, that.nodes ) ) {
return false;
}
if ( !Arrays.equals( types, that.types ) ) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = Arrays.hashCode( nodes );
result = 31 * result + Arrays.hashCode( types );
return result;
}
@Override
public String toString() {
return "DirectedEdgeMeta{" +
"nodes=" + Arrays.toString( nodes ) +
", types=" + Arrays.toString( types ) +
'}';
}
/**
* Given the edge serialization, load all shard in the shard group
*/
public abstract Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order );
/**
* Write the edge for this meta data to the target edge
* @param shardedEdgeSerialization
* @param edgeColumnFamilies
* @param scope
* @param targetShard
* @param edge
* @param timestamp The timestamp on the operation
* @return
*/
public abstract MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp );
/**
* Delete the edge for this meta data from the shard
* @param shardedEdgeSerialization
* @param edgeColumnFamilies
* @param scope
* @param sourceShard
* @param edge
* @param timestamp The timestamp on the operation
* @return
*/
public abstract MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp );
/**
* Get the type of this directed edge
*/
public abstract MetaType getType();
public enum MetaType {
SOURCE( 0 ),
SOURCETARGET( 1 ),
TARGET( 2 ),
TARGETSOURCE( 3 ),
VERSIONS( 4 );
private final int storageValue;
MetaType( final int storageValue ) {this.storageValue = storageValue;}
public int getStorageValue() {
return storageValue;
}
/**
* Get value from storageValue
*/
public static MetaType fromStorage( final int ordinal ) {
return mappings.get( ordinal );
}
private static Map<Integer, MetaType> mappings = new HashMap<Integer, MetaType>();
static {
for ( MetaType meta : MetaType.values() ) {
mappings.put( meta.storageValue, meta );
}
}
}
/**
* Created directed edge meta data from source node
*/
public static DirectedEdgeMeta fromSourceNode( final Id sourceId, final String edgeType ) {
return fromSourceNode(
new DirectedEdgeMeta.NodeMeta[] { new DirectedEdgeMeta.NodeMeta( sourceId, NodeType.SOURCE ) },
new String[] { edgeType } );
}
/**
* Return meta data from the source node by edge type
*/
private static DirectedEdgeMeta fromSourceNode( final NodeMeta[] nodes, final String[] types ) {
return new DirectedEdgeMeta( nodes, types ) {
@Override
public Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order ) {
final Id sourceId = nodes[0].id;
final String edgeType = types[0];
final SearchByEdgeType search = new SimpleSearchByEdgeType( sourceId, edgeType, maxValue, order,
Optional.<Edge>absent());
return serialization.getEdgesFromSource( edgeColumnFamilies, scope, search, shards );
}
@Override
public MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.writeEdgeFromSource( edgeColumnFamilies, scope, edge, Collections.singleton( targetShard ),
this, timestamp );
}
@Override
public MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.deleteEdgeFromSource( edgeColumnFamilies, scope, edge, Collections.singleton( sourceShard ),
this, timestamp );
}
@Override
public MetaType getType() {
return MetaType.SOURCE;
}
};
}
/**
* Return meta data that represents a source node with edge type and target type
*/
public static DirectedEdgeMeta fromSourceNodeTargetType( final Id sourceId, final String edgeType,
final String targetType ) {
return fromSourceNodeTargetType(
new DirectedEdgeMeta.NodeMeta[] { new DirectedEdgeMeta.NodeMeta( sourceId, NodeType.SOURCE ) },
new String[] { edgeType, targetType } );
}
/**
* Return meta data that represents a source node with edge type and target type
*/
private static DirectedEdgeMeta fromSourceNodeTargetType( NodeMeta[] nodes, String[] types ) {
return new DirectedEdgeMeta( nodes, types ) {
@Override
public Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order ) {
//
final Id sourceId = nodes[0].id;
final String edgeType = types[0];
final String targetType = types[1];
final SearchByIdType search =
new SimpleSearchByIdType( sourceId, edgeType, maxValue, order, targetType, Optional.<Edge>absent() );
return serialization.getEdgesFromSourceByTargetType( edgeColumnFamilies, scope, search, shards );
}
@Override
public MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization.writeEdgeFromSourceWithTargetType( edgeColumnFamilies, scope, edge,
Collections.singleton( targetShard ), this, timestamp );
}
@Override
public MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization.deleteEdgeFromSourceWithTargetType( edgeColumnFamilies, scope, edge,
Collections.singleton( sourceShard ), this, timestamp );
}
@Override
public MetaType getType() {
return MetaType.SOURCETARGET;
}
};
}
public static DirectedEdgeMeta fromTargetNode( final Id targetId, final String edgeType ) {
return fromTargetNode(
new DirectedEdgeMeta.NodeMeta[] { new DirectedEdgeMeta.NodeMeta( targetId, NodeType.TARGET ) },
new String[] { edgeType } );
}
/**
* Return meta data that represents from a target node by edge type
*/
private static DirectedEdgeMeta fromTargetNode( final NodeMeta[] nodes, final String[] types ) {
return new DirectedEdgeMeta( nodes, types ) {
@Override
public Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order ) {
final Id targetId = nodes[0].id;
final String edgeType = types[0];
final SearchByEdgeType search = new SimpleSearchByEdgeType( targetId, edgeType, maxValue, order, Optional.<Edge>absent());
return serialization.getEdgesToTarget( edgeColumnFamilies, scope, search, shards );
}
@Override
public MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.writeEdgeToTarget( edgeColumnFamilies, scope, edge, Collections.singleton( targetShard ),
this, timestamp );
}
@Override
public MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.deleteEdgeToTarget( edgeColumnFamilies, scope, edge, Collections.singleton( sourceShard ),
this, timestamp );
}
@Override
public MetaType getType() {
return MetaType.TARGET;
}
};
}
public static DirectedEdgeMeta fromTargetNodeSourceType( final Id targetId, final String edgeType,
final String sourceType ) {
return fromTargetNodeSourceType(
new DirectedEdgeMeta.NodeMeta[] { new DirectedEdgeMeta.NodeMeta( targetId, NodeType.TARGET ) },
new String[] { edgeType, sourceType } );
}
/**
* Return meta data that represents a target node and a source node type
*/
private static DirectedEdgeMeta fromTargetNodeSourceType( final NodeMeta[] nodes, final String[] types ) {
return new DirectedEdgeMeta( nodes, types ) {
@Override
public Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order ) {
final Id targetId = nodes[0].id;
final String edgeType = types[0];
final String sourceType = types[1];
final SearchByIdType search =
new SimpleSearchByIdType( targetId, edgeType, maxValue, order, sourceType, Optional.absent() );
return serialization.getEdgesToTargetBySourceType( edgeColumnFamilies, scope, search, shards );
}
@Override
public MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization.writeEdgeToTargetWithSourceType( edgeColumnFamilies, scope, edge,
Collections.singleton( targetShard ), this, timestamp );
}
@Override
public MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization.deleteEdgeToTargetWithSourceType( edgeColumnFamilies, scope, edge,
Collections.singleton( sourceShard ), this, timestamp );
}
@Override
public MetaType getType() {
return MetaType.TARGETSOURCE;
}
};
}
/**
* Return meta data that represents an entire edge
*/
public static DirectedEdgeMeta fromEdge( final Id sourceId, final Id targetId, final String edgeType ) {
return fromEdge( new DirectedEdgeMeta.NodeMeta[] {
new DirectedEdgeMeta.NodeMeta( sourceId, NodeType.SOURCE ),
new DirectedEdgeMeta.NodeMeta( targetId, NodeType.TARGET )
}, new String[] { edgeType } );
}
/**
* Return meta data that represents an entire edge
*/
private static DirectedEdgeMeta fromEdge( final NodeMeta[] nodes, final String[] types ) {
return new DirectedEdgeMeta( nodes, types ) {
@Override
public Iterator<MarkedEdge> loadEdges( final ShardedEdgeSerialization serialization,
final EdgeColumnFamilies edgeColumnFamilies,
final ApplicationScope scope, final Collection<Shard> shards,
final long maxValue, final SearchByEdgeType.Order order ) {
final Id sourceId = nodes[0].id;
final Id targetId = nodes[1].id;
final String edgeType = types[0];
final SimpleSearchByEdge search =
new SimpleSearchByEdge( sourceId, edgeType, targetId, maxValue, order, Optional.absent() );
return serialization.getEdgeVersions( edgeColumnFamilies, scope, search, shards );
}
@Override
public MutationBatch writeEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard targetShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.writeEdgeVersions( edgeColumnFamilies, scope, edge, Collections.singleton( targetShard ),
this, timestamp );
}
@Override
public MutationBatch deleteEdge( final ShardedEdgeSerialization shardedEdgeSerialization,
final EdgeColumnFamilies edgeColumnFamilies, final ApplicationScope scope,
final Shard sourceShard, final MarkedEdge edge, final UUID timestamp ) {
return shardedEdgeSerialization
.deleteEdgeVersions( edgeColumnFamilies, scope, edge, Collections.singleton( sourceShard ),
this, timestamp );
}
@Override
public MetaType getType() {
return MetaType.VERSIONS;
}
};
}
/**
* Create a directed edge from the stored meta data
*
* @param metaType The meta type stored
* @param nodes The metadata of the nodes
* @param types The types in the meta data
*/
public static DirectedEdgeMeta fromStorage( final MetaType metaType, final NodeMeta[] nodes,
final String[] types ) {
switch ( metaType ) {
case SOURCE:
return fromSourceNode( nodes, types );
case SOURCETARGET:
return fromSourceNodeTargetType( nodes, types );
case TARGET:
return fromTargetNode( nodes, types );
case TARGETSOURCE:
return fromTargetNodeSourceType( nodes, types );
case VERSIONS:
return fromEdge( nodes, types );
default:
throw new UnsupportedOperationException( "No supported meta type found" );
}
}
}