// Copyright 2017 JanusGraph Authors
//
// Licensed 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.janusgraph.graphdb.types.vertices;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.*;
import org.janusgraph.core.JanusGraphEdge;
import org.janusgraph.core.JanusGraphVertexProperty;
import org.janusgraph.core.JanusGraphVertex;
import org.janusgraph.core.JanusGraphVertexQuery;
import org.janusgraph.core.schema.SchemaStatus;
import org.janusgraph.graphdb.internal.JanusGraphSchemaCategory;
import org.janusgraph.graphdb.transaction.RelationConstructor;
import org.janusgraph.graphdb.transaction.StandardJanusGraphTx;
import org.janusgraph.graphdb.types.*;
import org.janusgraph.graphdb.types.indextype.CompositeIndexTypeWrapper;
import org.janusgraph.graphdb.types.indextype.MixedIndexTypeWrapper;
import org.janusgraph.graphdb.types.system.BaseKey;
import org.janusgraph.graphdb.types.system.BaseLabel;
import org.janusgraph.graphdb.vertices.CacheVertex;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import javax.annotation.Nullable;
public class JanusGraphSchemaVertex extends CacheVertex implements SchemaSource {
public JanusGraphSchemaVertex(StandardJanusGraphTx tx, long id, byte lifecycle) {
super(tx, id, lifecycle);
}
private String name = null;
@Override
public String name() {
if (name == null) {
JanusGraphVertexProperty<String> p;
if (isLoaded()) {
StandardJanusGraphTx tx = tx();
p = (JanusGraphVertexProperty) Iterables.getOnlyElement(RelationConstructor.readRelation(this,
tx.getGraph().getSchemaCache().getSchemaRelations(longId(), BaseKey.SchemaName, Direction.OUT),
tx), null);
} else {
p = Iterables.getOnlyElement(query().type(BaseKey.SchemaName).properties(), null);
}
Preconditions.checkState(p!=null,"Could not find type for id: %s", longId());
name = p.value();
}
assert name != null;
return JanusGraphSchemaCategory.getName(name);
}
@Override
protected Vertex getVertexLabelInternal() {
return null;
}
private TypeDefinitionMap definition = null;
@Override
public TypeDefinitionMap getDefinition() {
TypeDefinitionMap def = definition;
if (def == null) {
def = new TypeDefinitionMap();
Iterable<JanusGraphVertexProperty> ps;
if (isLoaded()) {
StandardJanusGraphTx tx = tx();
ps = (Iterable)RelationConstructor.readRelation(this,
tx.getGraph().getSchemaCache().getSchemaRelations(longId(), BaseKey.SchemaDefinitionProperty, Direction.OUT),
tx);
} else {
ps = query().type(BaseKey.SchemaDefinitionProperty).properties();
}
for (JanusGraphVertexProperty property : ps) {
TypeDefinitionDescription desc = property.valueOrNull(BaseKey.SchemaDefinitionDesc);
Preconditions.checkArgument(desc!=null && desc.getCategory().isProperty());
def.setValue(desc.getCategory(), property.value());
}
assert def.size()>0;
definition = def;
}
assert def!=null;
return def;
}
private ListMultimap<TypeDefinitionCategory,Entry> outRelations = null;
private ListMultimap<TypeDefinitionCategory,Entry> inRelations = null;
@Override
public Iterable<Entry> getRelated(TypeDefinitionCategory def, Direction dir) {
assert dir==Direction.OUT || dir==Direction.IN;
ListMultimap<TypeDefinitionCategory,Entry> rels = dir==Direction.OUT?outRelations:inRelations;
if (rels==null) {
ImmutableListMultimap.Builder<TypeDefinitionCategory,Entry> b = ImmutableListMultimap.builder();
Iterable<JanusGraphEdge> edges;
if (isLoaded()) {
StandardJanusGraphTx tx = tx();
edges = (Iterable)RelationConstructor.readRelation(this,
tx.getGraph().getSchemaCache().getSchemaRelations(longId(), BaseLabel.SchemaDefinitionEdge, dir),
tx);
} else {
edges = query().type(BaseLabel.SchemaDefinitionEdge).direction(dir).edges();
}
for (JanusGraphEdge edge: edges) {
JanusGraphVertex oth = edge.vertex(dir.opposite());
assert oth instanceof JanusGraphSchemaVertex;
TypeDefinitionDescription desc = edge.valueOrNull(BaseKey.SchemaDefinitionDesc);
Object modifier = null;
if (desc.getCategory().hasDataType()) {
assert desc.getModifier()!=null && desc.getModifier().getClass().equals(desc.getCategory().getDataType());
modifier = desc.getModifier();
}
b.put(desc.getCategory(), new Entry((JanusGraphSchemaVertex) oth, modifier));
}
rels = b.build();
if (dir==Direction.OUT) outRelations=rels;
else inRelations=rels;
}
assert rels!=null;
return rels.get(def);
}
/**
* Resets the internal caches used to speed up lookups on this index type.
* This is needed when the type gets modified in the {@link org.janusgraph.graphdb.database.management.ManagementSystem}.
*/
@Override
public void resetCache() {
name = null;
definition=null;
outRelations=null;
inRelations=null;
}
public Iterable<JanusGraphEdge> getEdges(final TypeDefinitionCategory def, final Direction dir) {
return getEdges(def,dir,null);
}
public Iterable<JanusGraphEdge> getEdges(final TypeDefinitionCategory def, final Direction dir, JanusGraphSchemaVertex other) {
JanusGraphVertexQuery query = query().type(BaseLabel.SchemaDefinitionEdge).direction(dir);
if (other!=null) query.adjacent(other);
return Iterables.filter(query.edges(),new Predicate<JanusGraphEdge>() {
@Override
public boolean apply(@Nullable JanusGraphEdge edge) {
TypeDefinitionDescription desc = edge.valueOrNull(BaseKey.SchemaDefinitionDesc);
return desc.getCategory()==def;
}
});
}
@Override
public String toString() {
return name();
}
@Override
public SchemaStatus getStatus() {
return getDefinition().getValue(TypeDefinitionCategory.STATUS,SchemaStatus.class);
}
@Override
public IndexType asIndexType() {
Preconditions.checkArgument(getDefinition().containsKey(TypeDefinitionCategory.INTERNAL_INDEX),"Schema vertex is not a type vertex: [%s,%s]", longId(), name());
if (getDefinition().<Boolean>getValue(TypeDefinitionCategory.INTERNAL_INDEX)) {
return new CompositeIndexTypeWrapper(this);
} else {
return new MixedIndexTypeWrapper(this);
}
}
}