Package com.orientechnologies.orient.core.db.graph

Source Code of com.orientechnologies.orient.core.db.graph.OGraphDatabase

/*
* Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
*
* 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 com.orientechnologies.orient.core.db.graph;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.orientechnologies.orient.core.db.ODatabase;
import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.ORecordLazySet;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.iterator.ORecordIteratorClass;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.tx.OTransactionNoTx;

/**
* Super light GraphDB implementation on top of the underlying Document. The generated vertexes and edges are compatible with those
* of ODatabaseGraphTx and TinkerPop Blueprints implementation. This class is the fastest and lightest but you have ODocument
* instances and not regular ad-hoc POJO as for other implementations. You could use this one for bulk operations and the others for
* regular graph access.
*
* @author Luca Garulli
*
*/
public class OGraphDatabase extends ODatabaseDocumentTx {
  public static final String  VERTEX_CLASS_NAME        = "OGraphVertex";
  public static final String  VERTEX_FIELD_IN_EDGES    = "inEdges";
  public static final String  VERTEX_FIELD_OUT_EDGES  = "outEdges";

  public static final String  EDGE_CLASS_NAME          = "OGraphEdge";
  public static final String  EDGE_FIELD_IN            = "in";
  public static final String  EDGE_FIELD_OUT          = "out";
  public static final String  LABEL                    = "label";

  private boolean              safeMode                = false;
  protected OClass            vertexBaseClass;
  protected OClass            edgeBaseClass;

  public OGraphDatabase(final String iURL) {
    super(iURL);
  }

  @Override
  @SuppressWarnings("unchecked")
  public <THISDB extends ODatabase> THISDB open(final String iUserName, final String iUserPassword) {
    super.open(iUserName, iUserPassword);
    checkForGraphSchema();
    return (THISDB) this;
  }

  @Override
  @SuppressWarnings("unchecked")
  public <THISDB extends ODatabase> THISDB create() {
    super.create();
    checkForGraphSchema();
    return (THISDB) this;
  }

  @Override
  public void close() {
    super.close();
    vertexBaseClass = null;
    edgeBaseClass = null;
  }

  public long countVertexes() {
    return countClass(VERTEX_CLASS_NAME);
  }

  public long countEdges() {
    return countClass(EDGE_CLASS_NAME);
  }

  public Iterable<ODocument> browseVertices() {
    return browseElements(VERTEX_CLASS_NAME, true);
  }

  public Iterable<ODocument> browseVertices(final boolean iPolymorphic) {
    return browseElements(VERTEX_CLASS_NAME, iPolymorphic);
  }

  public Iterable<ODocument> browseEdges() {
    return browseElements(EDGE_CLASS_NAME, true);
  }

  public Iterable<ODocument> browseEdges(final boolean iPolymorphic) {
    return browseElements(EDGE_CLASS_NAME, iPolymorphic);
  }

  public Iterable<ODocument> browseElements(final String iClass, final boolean iPolymorphic) {
    return new ORecordIteratorClass<ODocument>(this, (ODatabaseRecordAbstract) getUnderlying(), iClass, iPolymorphic);
  }

  public ODocument createVertex() {
    return createVertex(null);
  }

  public ODocument createVertex(String iClassName) {
    if (iClassName == null)
      iClassName = VERTEX_CLASS_NAME;
    else
      checkVertexClass(iClassName);

    return new ODocument(this, iClassName);
  }

  public ODocument createEdge(final ORID iSourceVertexRid, final ORID iDestVertexRid) {
    return createEdge(iSourceVertexRid, iDestVertexRid, null);
  }

  public ODocument createEdge(final ORID iSourceVertexRid, final ORID iDestVertexRid, final String iClassName) {
    final ODocument sourceVertex = load(iSourceVertexRid);
    if (sourceVertex == null)
      throw new IllegalArgumentException("Source vertex '" + iSourceVertexRid + "' doesn't exist");

    final ODocument destVertex = load(iDestVertexRid);
    if (destVertex == null)
      throw new IllegalArgumentException("Source vertex '" + iDestVertexRid + "' doesn't exist");

    return createEdge(sourceVertex, destVertex, iClassName);
  }

  public void removeVertex(final ODocument iVertex) {
    final boolean safeMode = beginBlock();

    try {
      ODocument otherVertex;
      Set<ODocument> otherEdges;

      // REMOVE OUT EDGES
      Set<ODocument> edges = iVertex.field(VERTEX_FIELD_OUT_EDGES);
      if (edges != null) {
        for (ODocument edge : edges) {
          if (edge != null) {
            otherVertex = edge.field(EDGE_FIELD_IN);
            if (otherVertex != null) {
              otherEdges = otherVertex.field(VERTEX_FIELD_IN_EDGES);
              if (otherEdges != null && otherEdges.remove(edge))
                save(otherVertex);
            }
            delete(edge);
          }
        }
        edges.clear();
        iVertex.field(VERTEX_FIELD_OUT_EDGES, edges);
      }

      // REMOVE IN EDGES
      edges = iVertex.field(VERTEX_FIELD_IN_EDGES);
      if (edges != null) {
        for (ODocument edge : edges) {
          if (edge != null) {
            otherVertex = edge.field(EDGE_FIELD_OUT);
            if (otherVertex != null) {
              otherEdges = otherVertex.field(VERTEX_FIELD_OUT_EDGES);
              if (otherEdges != null && otherEdges.remove(edge))
                save(otherVertex);
            }
            delete(edge);
          }
        }
        edges.clear();
        iVertex.field(VERTEX_FIELD_IN_EDGES, edges);
      }

      // DELETE VERTEX AS DOCUMENT
      delete(iVertex);

      commitBlock(safeMode);

    } catch (RuntimeException e) {
      rollbackBlock(safeMode);
      throw e;
    }
  }

  @SuppressWarnings("unchecked")
  public void removeEdge(final ODocument iEdge) {
    final boolean safeMode = beginBlock();

    try {
      final ODocument outVertex = iEdge.field(EDGE_FIELD_OUT);
      if (outVertex != null) {
        Set<ODocument> outEdges = ((Set<ODocument>) outVertex.field(VERTEX_FIELD_OUT_EDGES));
        if (outEdges != null)
          outEdges.remove(iEdge);
      }

      final ODocument inVertex = iEdge.field(EDGE_FIELD_IN);
      if (inVertex != null) {
        Set<ODocument> inEdges = ((Set<ODocument>) inVertex.field(VERTEX_FIELD_IN_EDGES));
        if (inEdges != null)
          inEdges.remove(iEdge);
      }

      delete(iEdge);

      if (outVertex != null)
        save(outVertex);
      if (inVertex != null)
        save(inVertex);

      commitBlock(safeMode);

    } catch (RuntimeException e) {
      rollbackBlock(safeMode);
      throw e;
    }
  }

  public ODocument createEdge(final ODocument iSourceVertex, final ODocument iDestVertex) {
    return createEdge(iSourceVertex, iDestVertex, null);
  }

  public ODocument createEdge(final ODocument iOutVertex, final ODocument iInVertex, final String iClassName) {
    if (iOutVertex == null)
      throw new IllegalArgumentException("iOutVertex is null");

    if (iInVertex == null)
      throw new IllegalArgumentException("iInVertex is null");

    checkVertexClass(iClassName);

    final boolean safeMode = beginBlock();

    try {
      iInVertex.setDatabase(this);
      iOutVertex.setDatabase(this);

      final ODocument edge = new ODocument(this, iClassName != null ? iClassName : EDGE_CLASS_NAME);
      edge.field(EDGE_FIELD_OUT, iOutVertex);
      edge.field(EDGE_FIELD_IN, iInVertex);

      ORecordLazySet outEdges = ((ORecordLazySet) iOutVertex.field(VERTEX_FIELD_OUT_EDGES));
      if (outEdges == null) {
        outEdges = new ORecordLazySet(iOutVertex);
        iOutVertex.field(VERTEX_FIELD_OUT_EDGES, outEdges);
      }
      outEdges.add(edge);

      ORecordLazySet inEdges = ((ORecordLazySet) iInVertex.field(VERTEX_FIELD_IN_EDGES));
      if (inEdges == null) {
        inEdges = new ORecordLazySet(iInVertex);
        iInVertex.field(VERTEX_FIELD_IN_EDGES, inEdges);
      }
      inEdges.add(edge);

      if (safeMode) {
        save(edge);
        commitBlock(safeMode);
      }

      return edge;

    } catch (RuntimeException e) {
      rollbackBlock(safeMode);
      throw e;
    }
  }

  /**
   * Returns all the edges between the vertexes iVertex1 and iVertex2.
   *
   * @param iVertex1
   *          First Vertex
   * @param iVertex2
   *          Second Vertex
   * @return The Set with the common Edges between the two vertexes. If edges aren't found the set is empty
   */
  public Set<ODocument> getEdgesBetweenVertexes(final ODocument iVertex1, final ODocument iVertex2) {
    return getEdgesBetweenVertexes(iVertex1, iVertex2, null, null);
  }

  /**
   * Returns all the edges between the vertexes iVertex1 and iVertex2 with label between the array of labels passed as iLabels.
   *
   * @param iVertex1
   *          First Vertex
   * @param iVertex2
   *          Second Vertex
   * @param iLabels
   *          Array of strings with the labels to get as filter
   * @return The Set with the common Edges between the two vertexes. If edges aren't found the set is empty
   */
  public Set<ODocument> getEdgesBetweenVertexes(final ODocument iVertex1, final ODocument iVertex2, final String[] iLabels) {
    return getEdgesBetweenVertexes(iVertex1, iVertex2, iLabels, null);
  }

  /**
   * Returns all the edges between the vertexes iVertex1 and iVertex2 with label between the array of labels passed as iLabels and
   * with class between the array of class names passed as iClassNames.
   *
   * @param iVertex1
   *          First Vertex
   * @param iVertex2
   *          Second Vertex
   * @param iLabels
   *          Array of strings with the labels to get as filter
   * @param iClassNames
   *          Array of strings with the name of the classes to get as filter
   * @return The Set with the common Edges between the two vertexes. If edges aren't found the set is empty
   */
  public Set<ODocument> getEdgesBetweenVertexes(final ODocument iVertex1, final ODocument iVertex2, final String[] iLabels,
      final String[] iClassNames) {

    final Set<ODocument> result = new HashSet<ODocument>();

    if (iVertex1 != null && iVertex2 != null) {
      // CHECK OUT EDGES
      for (OIdentifiable e : getOutEdges(iVertex1)) {
        final ODocument edge = (ODocument) e;

        if (checkEdge(edge, iLabels, iClassNames)) {
          if (edge.<ODocument> field("in").equals(iVertex2))
            result.add(edge);
        }
      }

      // CHECK IN EDGES
      for (OIdentifiable e : getInEdges(iVertex1)) {
        final ODocument edge = (ODocument) e;

        if (checkEdge(edge, iLabels, iClassNames)) {
          if (edge.<ODocument> field("out").equals(iVertex2))
            result.add(edge);
        }
      }
    }

    return result;
  }

  public Set<OIdentifiable> getOutEdges(final ODocument iVertex) {
    return getOutEdges(iVertex, null);
  }

  /**
   * Retrieves the outgoing edges of vertex iVertex having label equals to iLabel.
   *
   * @param iVertex
   *          Target vertex
   * @param iLabel
   *          Label to search
   * @return
   */
  public Set<OIdentifiable> getOutEdges(final ODocument iVertex, final String iLabel) {
    checkVertexClass(iVertex);

    final ORecordLazySet set = iVertex.field(VERTEX_FIELD_OUT_EDGES);

    if (iLabel == null)
      // RETURN THE ENTIRE COLLECTION
      if (set != null)
        return Collections.unmodifiableSet(set);
      else
        return Collections.emptySet();

    // FILTER BY LABEL
    final ORecordLazySet result = new ORecordLazySet(underlying);
    if (set != null)
      for (OIdentifiable item : set) {
        if (iLabel == null || iLabel.equals(((ODocument) item).field(LABEL)))
          result.add(item);
      }

    return result;
  }

  /**
   * Retrieves the outgoing edges of vertex iVertex having the requested properties iProperties set to the passed values
   *
   * @param iVertex
   *          Target vertex
   * @param iProperties
   *          Map where keys are property names and values the expected values
   * @return
   */
  public Set<OIdentifiable> getOutEdgesHavingProperties(final ODocument iVertex, final Map<String, Object> iProperties) {
    checkVertexClass(iVertex);

    return filterEdgesByProperties((ORecordLazySet) iVertex.field(VERTEX_FIELD_OUT_EDGES), iProperties);
  }

  /**
   * Retrieves the outgoing edges of vertex iVertex having the requested properties iProperties
   *
   * @param iVertex
   *          Target vertex
   * @param iProperties
   *          Map where keys are property names and values the expected values
   * @return
   */
  public Set<OIdentifiable> getOutEdgesHavingProperties(final ODocument iVertex, Iterable<String> iProperties) {
    checkVertexClass(iVertex);

    return filterEdgesByProperties((ORecordLazySet) iVertex.field(VERTEX_FIELD_OUT_EDGES), iProperties);
  }

  public Set<OIdentifiable> getInEdges(final ODocument iVertex) {
    return getInEdges(iVertex, null);
  }

  public Set<OIdentifiable> getInEdges(final ODocument iVertex, final String iLabel) {
    checkVertexClass(iVertex);

    final ORecordLazySet set = iVertex.field(VERTEX_FIELD_IN_EDGES);

    if (iLabel == null)
      // RETURN THE ENTIRE COLLECTION
      if (set != null)
        return Collections.unmodifiableSet(set);
      else
        return Collections.emptySet();

    // FILTER BY LABEL
    final ORecordLazySet result = new ORecordLazySet(underlying);
    if (set != null)
      for (OIdentifiable item : set) {
        if (iLabel == null || iLabel.equals(((ODocument) item).field(LABEL)))
          result.add(item);
      }

    return result;
  }

  /**
   * Retrieves the incoming edges of vertex iVertex having the requested properties iProperties
   *
   * @param iVertex
   *          Target vertex
   * @param iProperties
   *          Map where keys are property names and values the expected values
   * @return
   */
  public Set<OIdentifiable> getInEdgesHavingProperties(final ODocument iVertex, Iterable<String> iProperties) {
    checkVertexClass(iVertex);

    return filterEdgesByProperties((ORecordLazySet) iVertex.field(VERTEX_FIELD_IN_EDGES), iProperties);
  }

  /**
   * Retrieves the incoming edges of vertex iVertex having the requested properties iProperties set to the passed values
   *
   * @param iVertex
   *          Target vertex
   * @param iProperties
   *          Map where keys are property names and values the expected values
   * @return
   */
  public Set<OIdentifiable> getInEdgesHavingProperties(final ODocument iVertex, final Map<String, Object> iProperties) {
    checkVertexClass(iVertex);
    return filterEdgesByProperties((ORecordLazySet) iVertex.field(VERTEX_FIELD_IN_EDGES), iProperties);
  }

  public ODocument getInVertex(final ODocument iEdge) {
    checkEdgeClass(iEdge);
    return iEdge.field(EDGE_FIELD_IN);
  }

  public ODocument getOutVertex(final ODocument iEdge) {
    checkEdgeClass(iEdge);
    return iEdge.field(EDGE_FIELD_OUT);
  }

  public ODocument getRoot(final String iName) {
    return getDictionary().get(iName);
  }

  public ODocument getRoot(final String iName, final String iFetchPlan) {
    return getDictionary().get(iName, iFetchPlan);
  }

  public OGraphDatabase setRoot(final String iName, final ODocument iNode) {
    getDictionary().put(iName, iNode);
    return this;
  }

  public OClass createVertexType(final String iClassName) {
    return createVertexType(iClassName, vertexBaseClass);
  }

  public OClass createVertexType(final String iClassName, OClass iSuperClass) {
    return getMetadata().getSchema().createClass(iClassName, iSuperClass);
  }

  public OClass createVertexType(final String iClassName, final String iSuperClassName) {
    return createVertexType(iClassName, getMetadata().getSchema().getClass(iSuperClassName));
  }

  public OClass getVertexType(final String iClassName) {
    return getMetadata().getSchema().getClass(iClassName);
  }

  public OClass createEdgeType(final String iClassName) {
    return getMetadata().getSchema().createClass(iClassName, getMetadata().getSchema().getClass(EDGE_CLASS_NAME));
  }

  public OClass getEdgeType(final String iClassName) {
    return getMetadata().getSchema().getClass(iClassName);
  }

  public boolean isSafeMode() {
    return safeMode;
  }

  public void setSafeMode(boolean safeMode) {
    this.safeMode = safeMode;
  }

  public OClass getVertexBaseClass() {
    return vertexBaseClass;
  }

  public OClass getEdgeBaseClass() {
    return edgeBaseClass;
  }

  public Set<OIdentifiable> filterEdgesByProperties(final ORecordLazySet iEdges, final Iterable<String> iPropertyNames) {
    if (iPropertyNames == null)
      // RETURN THE ENTIRE COLLECTION
      if (iEdges != null)
        return Collections.unmodifiableSet(iEdges);
      else
        return Collections.emptySet();

    // FILTER BY PROPERTY VALUES
    final ORecordLazySet result = new ORecordLazySet(underlying);
    if (iEdges != null)
      for (OIdentifiable item : iEdges) {
        final ODocument doc = (ODocument) item;
        for (String propName : iPropertyNames) {
          if (doc.containsField(propName))
            // FOUND: ADD IT
            result.add(item);
        }
      }

    return result;
  }

  public Set<OIdentifiable> filterEdgesByProperties(final ORecordLazySet iEdges, final Map<String, Object> iProperties) {
    if (iProperties == null)
      // RETURN THE ENTIRE COLLECTION
      if (iEdges != null)
        return Collections.unmodifiableSet(iEdges);
      else
        return Collections.emptySet();

    // FILTER BY PROPERTY VALUES
    final ORecordLazySet result = new ORecordLazySet(underlying);
    if (iEdges != null)
      for (OIdentifiable item : iEdges) {
        final ODocument doc = (ODocument) item;
        for (Entry<String, Object> prop : iProperties.entrySet()) {
          if (prop.getKey() != null && doc.containsField(prop.getKey())) {
            if (prop.getValue() == null) {
              if (doc.field(prop.getKey()) == null)
                // BOTH NULL: ADD IT
                result.add(item);
            } else if (prop.getValue().equals(doc.field(prop.getKey())))
              // SAME VALUE: ADD IT
              result.add(item);
          }
        }
      }

    return result;
  }

  public void checkVertexClass(final ODocument iVertex) {
    if (!iVertex.getSchemaClass().isSubClassOf(vertexBaseClass))
      throw new IllegalArgumentException("The document received is not a vertex. Found class '" + iVertex.getSchemaClass() + "'");
  }

  public void checkVertexClass(final String iVertexTypeName) {
    if (iVertexTypeName != null) {
      final OClass cls = getMetadata().getSchema().getClass(iVertexTypeName);
      if (cls == null)
        throw new IllegalArgumentException("The class '" + iVertexTypeName + "' was not found");

      if (!cls.isSubClassOf(vertexBaseClass))
        throw new IllegalArgumentException("The class '" + iVertexTypeName + "' doesn't extend the vertex type");
    }
  }

  public void checkEdgeClass(final ODocument iEdge) {
    if (!iEdge.getSchemaClass().isSubClassOf(edgeBaseClass))
      throw new IllegalArgumentException("The document received is not an edge. Found class '" + iEdge.getSchemaClass() + "'");
  }

  protected boolean beginBlock() {
    if (safeMode && !(getTransaction() instanceof OTransactionNoTx)) {
      begin();
      return true;
    }
    return false;
  }

  protected void commitBlock(final boolean iOpenTxInSafeMode) {
    if (iOpenTxInSafeMode)
      commit();
  }

  protected void rollbackBlock(final boolean iOpenTxInSafeMode) {
    if (iOpenTxInSafeMode)
      rollback();
  }

  protected boolean checkEdge(final ODocument iEdge, final String[] iLabels, final String[] iClassNames) {
    boolean good = true;

    if (iClassNames != null) {
      // CHECK AGAINST CLASS NAMES
      good = false;
      for (String c : iClassNames) {
        if (c.equals(iEdge.getClassName())) {
          good = true;
          break;
        }
      }
    }

    if (good && iLabels != null) {
      // CHECK AGAINST LABELS
      good = false;
      for (String c : iLabels) {
        if (c.equals(iEdge.field(LABEL))) {
          good = true;
          break;
        }
      }
    }
    return good;
  }

  private void checkForGraphSchema() {
    vertexBaseClass = getMetadata().getSchema().getClass(VERTEX_CLASS_NAME);
    edgeBaseClass = getMetadata().getSchema().getClass(EDGE_CLASS_NAME);

    if (vertexBaseClass == null) {
      // CREATE THE META MODEL USING THE ORIENT SCHEMA
      vertexBaseClass = getMetadata().getSchema().createClass(VERTEX_CLASS_NAME, addPhysicalCluster(VERTEX_CLASS_NAME));
      vertexBaseClass.setShortName("V");
      vertexBaseClass.setOverSize(2);

      if (edgeBaseClass == null) {
        edgeBaseClass = getMetadata().getSchema().createClass(EDGE_CLASS_NAME, addPhysicalCluster(EDGE_CLASS_NAME));
        edgeBaseClass.setShortName("E");
      }

      vertexBaseClass.createProperty(VERTEX_FIELD_IN_EDGES, OType.LINKSET, edgeBaseClass);
      vertexBaseClass.createProperty(VERTEX_FIELD_OUT_EDGES, OType.LINKSET, edgeBaseClass);
      edgeBaseClass.createProperty(EDGE_FIELD_IN, OType.LINK, vertexBaseClass);
      edgeBaseClass.createProperty(EDGE_FIELD_OUT, OType.LINK, vertexBaseClass);
    } else {
      // @COMPATIBILITY 0.9.25
      if (vertexBaseClass.getProperty(VERTEX_FIELD_OUT_EDGES).getType() == OType.LINKLIST)
        vertexBaseClass.getProperty(VERTEX_FIELD_OUT_EDGES).setType(OType.LINKSET);
      if (vertexBaseClass.getProperty(VERTEX_FIELD_IN_EDGES).getType() == OType.LINKLIST)
        vertexBaseClass.getProperty(VERTEX_FIELD_IN_EDGES).setType(OType.LINKSET);
    }
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.db.graph.OGraphDatabase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.