protected void setTypeInternal(final OType iType) {
    getDatabase().checkSecurity(ORule.ResourceGeneric.SCHEMA, ORole.PERMISSION_UPDATE);

    acquireSchemaWriteLock();
    try {
      if (iType == globalRef.getType())
        // NO CHANGES
        return;

      if (!iType.getCastable().contains(globalRef.getType()))
        throw new IllegalArgumentException("Cannot change property type from " + globalRef.getType() + " to " + iType);

      this.globalRef = owner.owner.findOrCreateGlobalProperty(this.globalRef.getName(), iType);
    } finally {
      releaseSchemaWriteLock();
    }
  }

protected
void
setTypeInternal
(
final
OType
iType
)
{
getDatabase
(
)
.
checkSecurity
(
ORule
.
ResourceGeneric
.
SCHEMA
,
ORole
.
PERMISSION_UPDATE
)
;
acquireSchemaWriteLock
(
)
;
try
{
if
(
iType
==
globalRef
.
getType
(
)
)
// NO CHANGES
return
;
if
(
!
iType
.
getCastable
(
)
.
contains
(
globalRef
.
getType
(
)
)
)
throw
new
IllegalArgumentException
(
"Cannot change property type from "
+
globalRef
.
getType
(
)
+
" to "
+
iType
)
;
this
.
globalRef
=
owner
.
owner
.
findOrCreateGlobalProperty
(
this
.
globalRef
.
getName
(
)
,
iType
)
;
}
finally
{
releaseSchemaWriteLock
(
)
;
}
}

Change the type. It checks for compatibility between the change of type.

@param iType

Change the type . It checks for compatibility between the change of type .


public boolean canExecuteIndexedFunctionWithoutIndex(OFromClause target, OCommandContext context, OBinaryCompareOperator operator,
      Object right) {
    if (this.identifier == null) {
      return false;
    }
    return identifier.canExecuteIndexedFunctionWithoutIndex(target, context, operator, right);
  }

public boolean canExecuteIndexedFunctionWithoutIndex ( OFromClause target , OCommandContext context , OBinaryCompareOperator operator , Object right ) { if ( this . identifier == null ) { return false ; } return identifier . canExecuteIndexedFunctionWithoutIndex ( target , context , operator , right ) ; }

tests if current expression is an indexed funciton AND that function can also be executed without using the index

@param target   the query target
@param context  the execution context
@param operator
@param right

@return true if current expression is an indexed funciton AND that function can also be executed without using the index, false
otherwise


public long estimate(OClass oClass, long threshold, OCommandContext ctx) {
    long count = oClass.count();
    if (count > 1) {
      count = count / 2;
    }
    if (count < threshold) {
      return count;
    }

    long indexesCount = 0l;
    List<OAndBlock> flattenedConditions = flatten();
    Set<OIndex<?>> indexes = oClass.getIndexes();
    for (OAndBlock condition : flattenedConditions) {

      List<OBinaryCondition> indexedFunctConditions = condition
          .getIndexedFunctionConditions(oClass, (ODatabaseDocumentInternal) ctx.getDatabase());

      long conditionEstimation = Long.MAX_VALUE;

      if (indexedFunctConditions != null) {
        for (OBinaryCondition cond : indexedFunctConditions) {
          OFromClause from = new OFromClause(-1);
          OFromItem item = new OFromItem(-1);
          from.item = item;
          from.item.setIdentifier(new OIdentifier(oClass.getName()));
          long newCount = cond.estimateIndexed(from, ctx);
          if (newCount < conditionEstimation) {
            conditionEstimation = newCount;
          }
        }
      } else {
        Map<String, Object> conditions = getEqualityOperations(condition, ctx);

        for (OIndex index : indexes) {
          if (index.getType().equals(OClass.INDEX_TYPE.FULLTEXT.name()) || index.getType()
              .equals(OClass.INDEX_TYPE.FULLTEXT_HASH_INDEX.name())) {
            continue;
          }
          List<String> indexedFields = index.getDefinition().getFields();
          int nMatchingKeys = 0;
          for (String indexedField : indexedFields) {
            if (conditions.containsKey(indexedField)) {
              nMatchingKeys++;
            } else {
              break;
            }
          }
          if (nMatchingKeys > 0) {
            long newCount = estimateFromIndex(index, conditions, nMatchingKeys);
            if (newCount < conditionEstimation) {
              conditionEstimation = newCount;
            }
          }
        }
      }
      if (conditionEstimation > count) {
        return count;
      }
      indexesCount += conditionEstimation;
    }
    return Math.min(indexesCount, count);
  }

public long estimate ( OClass oClass , long threshold , OCommandContext ctx ) { long count = oClass . count ( ) ; if ( count > 1 ) { count = count / 2 ; } if ( count < threshold ) { return count ; } long indexesCount = 0l ; List < OAndBlock > flattenedConditions = flatten ( ) ; Set < OIndex < ? > > indexes = oClass . getIndexes ( ) ; for ( OAndBlock condition : flattenedConditions ) { List < OBinaryCondition > indexedFunctConditions = condition . getIndexedFunctionConditions ( oClass , ( ODatabaseDocumentInternal ) ctx . getDatabase ( ) ) ; long conditionEstimation = Long . MAX_VALUE ; if ( indexedFunctConditions != null ) { for ( OBinaryCondition cond : indexedFunctConditions ) { OFromClause from = new OFromClause ( - 1 ) ; OFromItem item = new OFromItem ( - 1 ) ; from . item = item ; from . item . setIdentifier ( new OIdentifier ( oClass . getName ( ) ) ) ; long newCount = cond . estimateIndexed ( from , ctx ) ; if ( newCount < conditionEstimation ) { conditionEstimation = newCount ; } } } else { Map < String , Object > conditions = getEqualityOperations ( condition , ctx ) ; for ( OIndex index : indexes ) { if ( index . getType ( ) . equals ( OClass . INDEX_TYPE . FULLTEXT . name ( ) ) || index . getType ( ) . equals ( OClass . INDEX_TYPE . FULLTEXT_HASH_INDEX . name ( ) ) ) { continue ; } List < String > indexedFields = index . getDefinition ( ) . getFields ( ) ; int nMatchingKeys = 0 ; for ( String indexedField : indexedFields ) { if ( conditions . containsKey ( indexedField ) ) { nMatchingKeys ++ ; } else { break ; } } if ( nMatchingKeys > 0 ) { long newCount = estimateFromIndex ( index , conditions , nMatchingKeys ) ; if ( newCount < conditionEstimation ) { conditionEstimation = newCount ; } } } } if ( conditionEstimation > count ) { return count ; } indexesCount += conditionEstimation ; } return Math . min ( indexesCount , count ) ; }

estimates how many items of this class will be returned applying this filter

@param oClass

@return an estimation of the number of records of this class returned applying this filter, 0 if and only if sure that no
records are returned


private static List<Class<?>> findClasses(final File iDirectory, String iPackageName, ClassLoader iClassLoader)
      throws ClassNotFoundException {
    final List<Class<?>> classes = new ArrayList<Class<?>>();
    if (!iDirectory.exists())
      return classes;

    iPackageName += "." + iDirectory.getName();

    String className;
    final File[] files = iDirectory.listFiles();
    if (files != null)
      for (File file : files) {
        if (file.isDirectory()) {
          if (file.getName().contains("."))
            continue;
          classes.addAll(findClasses(file, iPackageName, iClassLoader));
        } else if (file.getName().endsWith(CLASS_EXTENSION)) {
          className = file.getName().substring(0, file.getName().length() - CLASS_EXTENSION.length());
          classes.add(Class.forName(iPackageName + '.' + className, true, iClassLoader));
        }
      }
    return classes;
  }

private static List < Class < ? > > findClasses ( final File iDirectory , String iPackageName , ClassLoader iClassLoader ) throws ClassNotFoundException { final List < Class < ? > > classes = new ArrayList < Class < ? > > ( ) ; if ( ! iDirectory . exists ( ) ) return classes ; iPackageName += "." + iDirectory . getName ( ) ; String className ; final File [ ] files = iDirectory . listFiles ( ) ; if ( files != null ) for ( File file : files ) { if ( file . isDirectory ( ) ) { if ( file . getName ( ) . contains ( "." ) ) continue ; classes . addAll ( findClasses ( file , iPackageName , iClassLoader ) ) ; } else if ( file . getName ( ) . endsWith ( CLASS_EXTENSION ) ) { className = file . getName ( ) . substring ( 0 , file . getName ( ) . length ( ) - CLASS_EXTENSION . length ( ) ) ; classes . add ( Class . forName ( iPackageName + ' ' + className , true , iClassLoader ) ) ; } } return classes ; }

Recursive method used to find all classes in a given directory and subdirs.

@param iDirectory
The base directory
@param iPackageName
The package name for classes found inside the base directory
@return The classes
@throws ClassNotFoundException

Recursive method used to find all classes in a given directory and subdirs .


public static List<Class<?>> getClassessOfInterface(String thePackage, Class<?> theInterface, final ClassLoader iClassLoader) {
    List<Class<?>> classList = new ArrayList<Class<?>>();
    try {
      for (Class<?> discovered : getClassesFor(thePackage, iClassLoader)) {
        if (Arrays.asList(discovered.getInterfaces()).contains(theInterface)) {
          classList.add(discovered);
        }
      }
    } catch (ClassNotFoundException ex) {
      OLogManager.instance().error(null, "Error finding classes", ex);
    }

    return classList;
  }

public
static
List
<
Class
<
>
>
getClassessOfInterface
(
String
thePackage
,
Class
<
>
theInterface
,
final
ClassLoader
iClassLoader
)
{
List
<
Class
<
>
>
classList
=
new
ArrayList
<
Class
<
>
>
(
)
;
try
{
for
(
Class
<
>
discovered
:
getClassesFor
(
thePackage
,
iClassLoader
)
)
{
if
(
Arrays
.
asList
(
discovered
.
getInterfaces
(
)
)
.
contains
(
theInterface
)
)
{
classList
.
add
(
discovered
)
;
}
}
}
catch
(
ClassNotFoundException
ex
)
{
OLogManager
.
instance
(
)
.
error
(
,
"Error finding classes"
,
ex
)
;
}
return
classList
;
}

Filters discovered classes to see if they implement a given interface.

@param thePackage
@param theInterface
@param iClassLoader
@return The list of classes that implements the requested interface

Filters discovered classes to see if they implement a given interface .


public static Class<?> getGenericMultivalueType(final Field p) {
    if (p.getType() instanceof Class<?>) {
      final Type genericType = p.getGenericType();
      if (genericType != null && genericType instanceof ParameterizedType) {
        final ParameterizedType pt = (ParameterizedType) genericType;
        if (pt.getActualTypeArguments() != null && pt.getActualTypeArguments().length > 0) {
          if (((Class<?>) pt.getRawType()).isAssignableFrom(Map.class)) {
            if (pt.getActualTypeArguments()[1] instanceof Class<?>) {
              return (Class<?>) pt.getActualTypeArguments()[1];
            } else if (pt.getActualTypeArguments()[1] instanceof ParameterizedType)
              return (Class<?>) ((ParameterizedType) pt.getActualTypeArguments()[1]).getRawType();
          } else if (pt.getActualTypeArguments()[0] instanceof Class<?>) {
            return (Class<?>) pt.getActualTypeArguments()[0];
          } else if (pt.getActualTypeArguments()[0] instanceof ParameterizedType)
            return (Class<?>) ((ParameterizedType) pt.getActualTypeArguments()[0]).getRawType();
        }
      } else if (p.getType().isArray())
        return p.getType().getComponentType();
    }
    return null;
  }

public static Class < ? > getGenericMultivalueType ( final Field p ) { if ( p . getType ( ) instanceof Class < ? > ) { final Type genericType = p . getGenericType ( ) ; if ( genericType != null && genericType instanceof ParameterizedType ) { final ParameterizedType pt = ( ParameterizedType ) genericType ; if ( pt . getActualTypeArguments ( ) != null && pt . getActualTypeArguments ( ) . length > 0 ) { if ( ( ( Class < ? > ) pt . getRawType ( ) ) . isAssignableFrom ( Map . class ) ) { if ( pt . getActualTypeArguments ( ) [ 1 ] instanceof Class < ? > ) { return ( Class < ? > ) pt . getActualTypeArguments ( ) [ 1 ] ; } else if ( pt . getActualTypeArguments ( ) [ 1 ] instanceof ParameterizedType ) return ( Class < ? > ) ( ( ParameterizedType ) pt . getActualTypeArguments ( ) [ 1 ] ) . getRawType ( ) ; } else if ( pt . getActualTypeArguments ( ) [ 0 ] instanceof Class < ? > ) { return ( Class < ? > ) pt . getActualTypeArguments ( ) [ 0 ] ; } else if ( pt . getActualTypeArguments ( ) [ 0 ] instanceof ParameterizedType ) return ( Class < ? > ) ( ( ParameterizedType ) pt . getActualTypeArguments ( ) [ 0 ] ) . getRawType ( ) ; } } else if ( p . getType ( ) . isArray ( ) ) return p . getType ( ) . getComponentType ( ) ; } return null ; }

Returns the generic class of multi-value objects.

@param p
Field to examine
@return The Class<?> of generic type if any, otherwise null

Returns the generic class of multi - value objects .


@Override
  public Object evaluateRecord(final OIdentifiable iRecord, ODocument iCurrentResult, final OSQLFilterCondition iCondition,
      final Object iLeft, final Object iRight, OCommandContext iContext, final ODocumentSerializer serializer) {
    if (iLeft == null || iRight == null)
      return false;

    return iLeft.toString().indexOf(iRight.toString()) > -1;
  }

@ Override public Object evaluateRecord ( final OIdentifiable iRecord , ODocument iCurrentResult , final OSQLFilterCondition iCondition , final Object iLeft , final Object iRight , OCommandContext iContext , final ODocumentSerializer serializer ) { if ( iLeft == null || iRight == null ) return false ; return iLeft . toString ( ) . indexOf ( iRight . toString ( ) ) > - 1 ; }

This is executed on non - indexed fields .


protected OType deriveFieldType(ODocument iRecord, String fieldName, OType requestedFieldType) {

    // Schema defined types can not be ignored
    if (iRecord.getSchemaClass().existsProperty(fieldName)) {
      return iRecord.getSchemaClass().getProperty(fieldName).getType();
    }

    // New type
    if (requestedFieldType != null) {
      return requestedFieldType;
    }

    // Existing type (not fixed by the schema)
    return iRecord.fieldType(fieldName);
  }

Derives the type of a field in a document.

@param iRecord
@param fieldName
@param requestedFieldType
@return derived field type

Derives the type of a field in a document .


public void updateRecord(final ORecord record) {
    if (record.getIdentity().getClusterId() != excludedCluster && record.getIdentity().isValid() && !record.isDirty()
        && !ORecordVersionHelper.isTombstone(record.getVersion())) {
      if (underlying.get(record.getIdentity()) != record)
        underlying.put(record);
    }
  }

public void updateRecord ( final ORecord record ) { if ( record . getIdentity ( ) . getClusterId ( ) != excludedCluster && record . getIdentity ( ) . isValid ( ) && ! record . isDirty ( ) && ! ORecordVersionHelper . isTombstone ( record . getVersion ( ) ) ) { if ( underlying . get ( record . getIdentity ( ) ) != record ) underlying . put ( record ) ; } }

Pushes record to cache. Identifier of record used as access key

@param record
record that should be cached

Pushes record to cache . Identifier of record used as access key


public ORecord findRecord(final ORID rid) {
    ORecord record;
    record = underlying.get(rid);

    if (record != null)
      Orient.instance().getProfiler().updateCounter(CACHE_HIT, "Record found in Level1 Cache", 1L, "db.*.cache.level1.cache.found");
    else
      Orient.instance().getProfiler().updateCounter(CACHE_MISS, "Record not found in Level1 Cache", 1L,
          "db.*.cache.level1.cache.notFound");

    return record;
  }

public
ORecord
findRecord
(
final
ORID
rid
)
{
ORecord
record
;
record
=
underlying
.
get
(
rid
)
;
if
(
record
!=
)
Orient
.
instance
(
)
.
getProfiler
(
)
.
updateCounter
(
CACHE_HIT
,
"Record found in Level1 Cache"
,
1L
,
"db.*.cache.level1.cache.found"
)
;
else
Orient
.
instance
(
)
.
getProfiler
(
)
.
updateCounter
(
CACHE_MISS
,
"Record not found in Level1 Cache"
,
1L
,
"db.*.cache.level1.cache.notFound"
)
;
return
record
;
}

Looks up for record in cache by it's identifier. Optionally look up in secondary cache and update primary with found record

@param rid
unique identifier of record
@return record stored in cache if any, otherwise - {@code null}

Looks up for record in cache by it s identifier . Optionally look up in secondary cache and update primary with found record


private Map<String, Set<String>> getMinimalSetOfNodesForShardedQuery(String localNode, Map<String, Set<String>> clusterMap,
      Set<String> queryClusters) {
    //approximate algorithm, the problem is NP-complete
    Map<String, Set<String>> result = new LinkedHashMap<>();
    Set<String> uncovered = new HashSet<>();
    uncovered.addAll(queryClusters);
    uncovered = uncovered.stream().filter(x -> x != null).map(x -> x.toLowerCase(Locale.ENGLISH)).collect(Collectors.toSet());

    //try local node first
    Set<String> nextNodeClusters = new HashSet<>();
    Set<String> clustersForNode = clusterMap.get(localNode);
    if (clustersForNode != null) {
      nextNodeClusters.addAll(clustersForNode);
    }
    nextNodeClusters.retainAll(uncovered);
    if (nextNodeClusters.size() > 0) {
      result.put(localNode, nextNodeClusters);
      uncovered.removeAll(nextNodeClusters);
    }

    while (uncovered.size() > 0) {
      String nextNode = findItemThatCoversMore(uncovered, clusterMap);
      nextNodeClusters = new HashSet<>();
      nextNodeClusters.addAll(clusterMap.get(nextNode));
      nextNodeClusters.retainAll(uncovered);
      if (nextNodeClusters.size() == 0) {
        throw new OCommandExecutionException(
            "Cannot execute a sharded query: clusters [" + uncovered.stream().collect(Collectors.joining(", "))
                + "] are not present on any node" + "\n [" + clusterMap.entrySet().stream()
                .map(x -> "" + x.getKey() + ":(" + x.getValue().stream().collect(Collectors.joining(",")) + ")")
                .collect(Collectors.joining(", ")) + "]");
      }
      result.put(nextNode, nextNodeClusters);
      uncovered.removeAll(nextNodeClusters);
    }
    return result;
  }

given a cluster map and a set of clusters involved in a query, tries to calculate the minimum number of nodes that will have to
be involved in the query execution, with clusters involved for each node.

@param clusterMap
@param queryClusters

@return a map that has node names as a key and clusters (data files) for each node as a value

given a cluster map and a set of clusters involved in a query tries to calculate the minimum number of nodes that will have to be involved in the query execution with clusters involved for each node .


private static List<OAndBlock> moveFlattededEqualitiesLeft(List<OAndBlock> flattenedWhereClause) {
    if (flattenedWhereClause == null) {
      return null;
    }

    List<OAndBlock> result = new ArrayList<>();
    for (OAndBlock block : flattenedWhereClause) {
      List<OBooleanExpression> equalityExpressions = new ArrayList<>();
      List<OBooleanExpression> nonEqualityExpressions = new ArrayList<>();
      OAndBlock newBlock = block.copy();
      for (OBooleanExpression exp : newBlock.getSubBlocks()) {
        if (exp instanceof OBinaryCondition) {
          if (((OBinaryCondition) exp).getOperator() instanceof OEqualsCompareOperator) {
            equalityExpressions.add(exp);
          } else {
            nonEqualityExpressions.add(exp);
          }
        } else {
          nonEqualityExpressions.add(exp);
        }
      }
      OAndBlock newAnd = new OAndBlock(-1);
      newAnd.getSubBlocks().addAll(equalityExpressions);
      newAnd.getSubBlocks().addAll(nonEqualityExpressions);
      result.add(newAnd);
    }

    return result;
  }

private static List < OAndBlock > moveFlattededEqualitiesLeft ( List < OAndBlock > flattenedWhereClause ) { if ( flattenedWhereClause == null ) { return null ; } List < OAndBlock > result = new ArrayList <> ( ) ; for ( OAndBlock block : flattenedWhereClause ) { List < OBooleanExpression > equalityExpressions = new ArrayList <> ( ) ; List < OBooleanExpression > nonEqualityExpressions = new ArrayList <> ( ) ; OAndBlock newBlock = block . copy ( ) ; for ( OBooleanExpression exp : newBlock . getSubBlocks ( ) ) { if ( exp instanceof OBinaryCondition ) { if ( ( ( OBinaryCondition ) exp ) . getOperator ( ) instanceof OEqualsCompareOperator ) { equalityExpressions . add ( exp ) ; } else { nonEqualityExpressions . add ( exp ) ; } } else { nonEqualityExpressions . add ( exp ) ; } } OAndBlock newAnd = new OAndBlock ( - 1 ) ; newAnd . getSubBlocks ( ) . addAll ( equalityExpressions ) ; newAnd . getSubBlocks ( ) . addAll ( nonEqualityExpressions ) ; result . add ( newAnd ) ; } return result ; }

re-writes a list of flat AND conditions, moving left all the equality operations

@param flattenedWhereClause

@return

re - writes a list of flat AND conditions moving left all the equality operations


private static void addOrderByProjections(QueryPlanningInfo info) {
    if (info.orderApplied || info.expand || info.unwind != null || info.orderBy == null || info.orderBy.getItems().size() == 0
        || info.projection == null || info.projection.getItems() == null || (info.projection.getItems().size() == 1
        && info.projection.getItems().get(0).isAll())) {
      return;
    }

    OOrderBy newOrderBy = info.orderBy == null ? null : info.orderBy.copy();
    List<OProjectionItem> additionalOrderByProjections = calculateAdditionalOrderByProjections(info.projection.getAllAliases(),
        newOrderBy);
    if (additionalOrderByProjections.size() > 0) {
      info.orderBy = newOrderBy;//the ORDER BY has changed
    }
    if (additionalOrderByProjections.size() > 0) {
      info.projectionAfterOrderBy = new OProjection(-1);
      info.projectionAfterOrderBy.setItems(new ArrayList<>());
      for (String alias : info.projection.getAllAliases()) {
        info.projectionAfterOrderBy.getItems().add(projectionFromAlias(new OIdentifier(alias)));
      }

      for (OProjectionItem item : additionalOrderByProjections) {
        if (info.preAggregateProjection != null) {
          info.preAggregateProjection.getItems().add(item);
          info.aggregateProjection.getItems().add(projectionFromAlias(item.getAlias()));
          info.projection.getItems().add(projectionFromAlias(item.getAlias()));
        } else {
          info.projection.getItems().add(item);
        }
      }
    }
  }

private
static
void
addOrderByProjections
(
QueryPlanningInfo
info
)
{
if
(
info
.
orderApplied
||
info
.
expand
||
info
.
unwind
!=
||
info
.
orderBy
==
||
info
.
orderBy
.
getItems
(
)
.
size
(
)
==
0
||
info
.
projection
==
||
info
.
projection
.
getItems
(
)
==
||
(
info
.
projection
.
getItems
(
)
.
size
(
)
==
1
&&
info
.
projection
.
getItems
(
)
.
get
(
0
)
.
isAll
(
)
)
)
{
return
;
}
OOrderBy
newOrderBy
=
info
.
orderBy
==
:
info
.
orderBy
.
copy
(
)
;
List
<
OProjectionItem
>
additionalOrderByProjections
=
calculateAdditionalOrderByProjections
(
info
.
projection
.
getAllAliases
(
)
,
newOrderBy
)
;
if
(
additionalOrderByProjections
.
size
(
)
>
0
)
{
info
.
orderBy
=
newOrderBy
;
//the ORDER BY has changed
}
if
(
additionalOrderByProjections
.
size
(
)
>
0
)
{
info
.
projectionAfterOrderBy
=
new
OProjection
(
1
)
;
info
.
projectionAfterOrderBy
.
setItems
(
new
ArrayList
<>
(
)
)
;
for
(
String
alias
:
info
.
projection
.
getAllAliases
(
)
)
{
info
.
projectionAfterOrderBy
.
getItems
(
)
.
add
(
projectionFromAlias
(
new
OIdentifier
(
alias
)
)
)
;
}
for
(
OProjectionItem
item
:
additionalOrderByProjections
)
{
if
(
info
.
preAggregateProjection
!=
)
{
info
.
preAggregateProjection
.
getItems
(
)
.
add
(
item
)
;
info
.
aggregateProjection
.
getItems
(
)
.
add
(
projectionFromAlias
(
item
.
getAlias
(
)
)
)
;
info
.
projection
.
getItems
(
)
.
add
(
projectionFromAlias
(
item
.
getAlias
(
)
)
)
;
}
else
{
info
.
projection
.
getItems
(
)
.
add
(
item
)
;
}
}
}
}

creates additional projections for ORDER BY


private static void extractSubQueries(QueryPlanningInfo info) {
    SubQueryCollector collector = new SubQueryCollector();
    if (info.perRecordLetClause != null) {
      info.perRecordLetClause.extractSubQueries(collector);
    }
    int i = 0;
    int j = 0;
    for (Map.Entry<OIdentifier, OStatement> entry : collector.getSubQueries().entrySet()) {
      OIdentifier alias = entry.getKey();
      OStatement query = entry.getValue();
      if (query.refersToParent()) {
        addRecordLevelLet(info, alias, query, j++);
      } else {
        addGlobalLet(info, alias, query, i++);
      }
    }
    collector.reset();

    if (info.whereClause != null) {
      info.whereClause.extractSubQueries(collector);
    }
    if (info.projection != null) {
      info.projection.extractSubQueries(collector);
    }
    if (info.orderBy != null) {
      info.orderBy.extractSubQueries(collector);
    }
    if (info.groupBy != null) {
      info.groupBy.extractSubQueries(collector);
    }

    for (Map.Entry<OIdentifier, OStatement> entry : collector.getSubQueries().entrySet()) {
      OIdentifier alias = entry.getKey();
      OStatement query = entry.getValue();
      if (query.refersToParent()) {
        addRecordLevelLet(info, alias, query);
      } else {
        addGlobalLet(info, alias, query);
      }
    }
  }

private static void extractSubQueries ( QueryPlanningInfo info ) { SubQueryCollector collector = new SubQueryCollector ( ) ; if ( info . perRecordLetClause != null ) { info . perRecordLetClause . extractSubQueries ( collector ) ; } int i = 0 ; int j = 0 ; for ( Map . Entry < OIdentifier , OStatement > entry : collector . getSubQueries ( ) . entrySet ( ) ) { OIdentifier alias = entry . getKey ( ) ; OStatement query = entry . getValue ( ) ; if ( query . refersToParent ( ) ) { addRecordLevelLet ( info , alias , query , j ++ ) ; } else { addGlobalLet ( info , alias , query , i ++ ) ; } } collector . reset ( ) ; if ( info . whereClause != null ) { info . whereClause . extractSubQueries ( collector ) ; } if ( info . projection != null ) { info . projection . extractSubQueries ( collector ) ; } if ( info . orderBy != null ) { info . orderBy . extractSubQueries ( collector ) ; } if ( info . groupBy != null ) { info . groupBy . extractSubQueries ( collector ) ; } for ( Map . Entry < OIdentifier , OStatement > entry : collector . getSubQueries ( ) . entrySet ( ) ) { OIdentifier alias = entry . getKey ( ) ; OStatement query = entry . getValue ( ) ; if ( query . refersToParent ( ) ) { addRecordLevelLet ( info , alias , query ) ; } else { addGlobalLet ( info , alias , query ) ; } } }


private boolean isFromClusters(ORid rid, Set<String> filterClusters, ODatabase database) {
    if (filterClusters == null) {
      throw new IllegalArgumentException();
    }
    String clusterName = database.getClusterNameById(rid.getCluster().getValue().intValue());
    return filterClusters.contains(clusterName);
  }

private boolean isFromClusters ( ORid rid , Set < String > filterClusters , ODatabase database ) { if ( filterClusters == null ) { throw new IllegalArgumentException ( ) ; } String clusterName = database . getClusterNameById ( rid . getCluster ( ) . getValue ( ) . intValue ( ) ) ; return filterClusters . contains ( clusterName ) ; }

checks if this RID is from one of these clusters

@param rid
@param filterClusters
@param database

@return


private boolean handleClassWithIndexForSortOnly(OSelectExecutionPlan plan, OIdentifier queryTarget, Set<String> filterClusters,
      QueryPlanningInfo info, OCommandContext ctx, boolean profilingEnabled) {
    OSchema schema = getSchemaFromContext(ctx);
    OClass clazz = schema.getClass(queryTarget.getStringValue());
    if (clazz == null) {
      clazz = schema.getView(queryTarget.getStringValue());
      if (clazz == null) {
        throw new OCommandExecutionException("Class not found: " + queryTarget);
      }
    }

    for (OIndex idx : clazz.getIndexes().stream().filter(i -> i.supportsOrderedIterations()).filter(i -> i.getDefinition() != null)
        .collect(Collectors.toList())) {
      List<String> indexFields = idx.getDefinition().getFields();
      if (indexFields.size() < info.orderBy.getItems().size()) {
        continue;
      }
      boolean indexFound = true;
      String orderType = null;
      for (int i = 0; i < info.orderBy.getItems().size(); i++) {
        OOrderByItem orderItem = info.orderBy.getItems().get(i);
        if (orderItem.getCollate() != null) {
          return false;
        }
        String indexField = indexFields.get(i);
        if (i == 0) {
          orderType = orderItem.getType();
        } else {
          if (orderType == null || !orderType.equals(orderItem.getType())) {
            indexFound = false;
            break;//ASC/DESC interleaved, cannot be used with index.
          }
        }
        if (!(indexField.equals(orderItem.getAlias()) || isInOriginalProjection(indexField, orderItem.getAlias()))) {
          indexFound = false;
          break;
        }
      }
      if (indexFound && orderType != null) {
        plan.chain(new FetchFromIndexValuesStep(idx, orderType.equals(OOrderByItem.ASC), ctx, profilingEnabled));
        int[] filterClusterIds = null;
        if (filterClusters != null) {
          filterClusterIds = filterClusters.stream().map(name -> ctx.getDatabase().getClusterIdByName(name)).mapToInt(i -> i)
              .toArray();
        }
        plan.chain(new GetValueFromIndexEntryStep(ctx, filterClusterIds, profilingEnabled));
        if (info.serverToClusters.size() == 1) {
          info.orderApplied = true;
        }
        return true;
      }
    }
    return false;
  }

tries to use an index for sorting only. Also adds the fetch step to the execution plan

@param plan current execution plan
@param info the query planning information
@param ctx  the current context

@return true if it succeeded to use an index to sort, false otherwise.

tries to use an index for sorting only . Also adds the fetch step to the execution plan


private boolean isDiamondHierarchy(OClass clazz) {
    Set<OClass> traversed = new HashSet<>();
    List<OClass> stack = new ArrayList<>();
    stack.add(clazz);
    while (!stack.isEmpty()) {
      OClass current = stack.remove(0);
      traversed.add(current);
      for (OClass sub : current.getSubclasses()) {
        if (traversed.contains(sub)) {
          return true;
        }
        stack.add(sub);
        traversed.add(sub);
      }
    }
    return false;
  }

private boolean isDiamondHierarchy ( OClass clazz ) { Set < OClass > traversed = new HashSet <> ( ) ; List < OClass > stack = new ArrayList <> ( ) ; stack . add ( clazz ) ; while ( ! stack . isEmpty ( ) ) { OClass current = stack . remove ( 0 ) ; traversed . add ( current ) ; for ( OClass sub : current . getSubclasses ( ) ) { if ( traversed . contains ( sub ) ) { return true ; } stack . add ( sub ) ; traversed . add ( sub ) ; } } return false ; }

checks if a class is the top of a diamond hierarchy

@param clazz

@return


private Boolean getOrderDirection(QueryPlanningInfo info) {
    if (info.orderBy == null) {
      return null;
    }
    String result = null;
    for (OOrderByItem item : info.orderBy.getItems()) {
      if (result == null) {
        result = item.getType() == null ? OOrderByItem.ASC : item.getType();
      } else {
        String newType = item.getType() == null ? OOrderByItem.ASC : item.getType();
        if (!newType.equals(result)) {
          return null;
        }
      }
    }
    return result == null || result.equals(OOrderByItem.ASC);
  }

private Boolean getOrderDirection ( QueryPlanningInfo info ) { if ( info . orderBy == null ) { return null ; } String result = null ; for ( OOrderByItem item : info . orderBy . getItems ( ) ) { if ( result == null ) { result = item . getType ( ) == null ? OOrderByItem . ASC : item . getType ( ) ; } else { String newType = item . getType ( ) == null ? OOrderByItem . ASC : item . getType ( ) ; if ( ! newType . equals ( result ) ) { return null ; } } } return result == null || result . equals ( OOrderByItem . ASC ) ; }

returns TRUE if all the order clauses are ASC, FALSE if all are DESC, null otherwise

@return TRUE if all the order clauses are ASC, FALSE if all are DESC, null otherwise

returns TRUE if all the order clauses are ASC FALSE if all are DESC null otherwise


private boolean requiresMultipleIndexLookups(OAndBlock keyCondition) {
    for (OBooleanExpression oBooleanExpression : keyCondition.getSubBlocks()) {
      if (!(oBooleanExpression instanceof OBinaryCondition)) {
        return true;
      }
    }
    return false;
  }

private boolean requiresMultipleIndexLookups ( OAndBlock keyCondition ) { for ( OBooleanExpression oBooleanExpression : keyCondition . getSubBlocks ( ) ) { if ( ! ( oBooleanExpression instanceof OBinaryCondition ) ) { return true ; } } return false ; }

checks whether the condition has CONTAINSANY or similar expressions, that require multiple index evaluations

@param keyCondition

@return

checks whether the condition has CONTAINSANY or similar expressions that require multiple index evaluations


private IndexSearchDescriptor findBestIndexFor(OCommandContext ctx, Set<OIndex<?>> indexes, OAndBlock block, OClass clazz) {
    //get all valid index descriptors
    List<IndexSearchDescriptor> descriptors = indexes.stream().filter(x -> x.getInternal().canBeUsedInEqualityOperators())
        .map(index -> buildIndexSearchDescriptor(ctx, index, block, clazz)).filter(Objects::nonNull)
        .filter(x -> x.keyCondition != null).filter(x -> x.keyCondition.getSubBlocks().size() > 0).collect(Collectors.toList());

    List<IndexSearchDescriptor> fullTextIndexDescriptors = indexes.stream()
        .filter(idx->idx.getType().equalsIgnoreCase("FULLTEXT"))
        .filter(idx->!idx.getAlgorithm().equalsIgnoreCase("LUCENE"))
        .map(idx -> buildIndexSearchDescriptorForFulltext(ctx, idx, block, clazz)).filter(Objects::nonNull)
        .filter(x -> x.keyCondition != null).filter(x -> x.keyCondition.getSubBlocks().size() > 0).collect(Collectors.toList());

    descriptors.addAll(fullTextIndexDescriptors);

    //remove the redundant descriptors (eg. if I have one on [a] and one on [a, b], the first one is redundant, just discard it)
    descriptors = removePrefixIndexes(descriptors);

    //sort by cost
    List<OPair<Integer, IndexSearchDescriptor>> sortedDescriptors = descriptors.stream()
        .map(x -> (OPair<Integer, IndexSearchDescriptor>) new OPair(x.cost(ctx), x)).sorted().collect(Collectors.toList());

    //get only the descriptors with the lowest cost
    descriptors = sortedDescriptors.isEmpty() ?
        Collections.emptyList() :
        sortedDescriptors.stream().filter(x -> x.key.equals(sortedDescriptors.get(0).key)).map(x -> x.value)
            .collect(Collectors.toList());

    //sort remaining by the number of indexed fields
    descriptors = descriptors.stream().sorted(Comparator.comparingInt(x -> x.keyCondition.getSubBlocks().size()))
        .collect(Collectors.toList());

    //get the one that has more indexed fields
    return descriptors.isEmpty() ? null : descriptors.get(descriptors.size() - 1);
  }

given a flat AND block and a set of indexes, returns the best index to be used to process it, with the complete description on
how to use it

@param ctx
@param indexes
@param block

@return

given a flat AND block and a set of indexes returns the best index to be used to process it with the complete description on how to use it


private IndexSearchDescriptor buildIndexSearchDescriptorForFulltext(OCommandContext ctx, OIndex<?> index, OAndBlock block, OClass clazz) {
    List<String> indexFields = index.getDefinition().getFields();
    OBinaryCondition keyCondition = new OBinaryCondition(-1);
    OIdentifier key = new OIdentifier("key");
    keyCondition.setLeft(new OExpression(key));
    boolean found = false;

    OAndBlock blockCopy = block.copy();
    Iterator<OBooleanExpression> blockIterator;

    OAndBlock indexKeyValue = new OAndBlock(-1);
    IndexSearchDescriptor result = new IndexSearchDescriptor();
    result.idx = index;
    result.keyCondition = indexKeyValue;
    for (String indexField : indexFields) {
      blockIterator = blockCopy.getSubBlocks().iterator();
      boolean breakHere = false;
      boolean indexFieldFound = false;
      while (blockIterator.hasNext()) {
        OBooleanExpression singleExp = blockIterator.next();
        if (singleExp instanceof OContainsTextCondition) {
          OExpression left = ((OContainsTextCondition) singleExp).getLeft();
          if (left.isBaseIdentifier()) {
            String fieldName = left.getDefaultAlias().getStringValue();
            if (indexField.equals(fieldName)) {
              found = true;
              indexFieldFound = true;
              OContainsTextCondition condition = new OContainsTextCondition(-1);
              condition.setLeft(left);
              condition.setRight(((OContainsTextCondition) singleExp).getRight().copy());
              indexKeyValue.getSubBlocks().add(condition);
              blockIterator.remove();
              break;
            }
          }
        }
      }
      if (breakHere || !indexFieldFound) {
        break;
      }
    }

    if (result.keyCondition.getSubBlocks().size() < index.getDefinition().getFields().size() && !index
        .supportsOrderedIterations()) {
      //hash indexes do not support partial key match
      return null;
    }

    if (found) {
      result.remainingCondition = blockCopy;
      return result;
    }
    return null;
  }

given a full text index and a flat AND block, returns a descriptor on how to process it with an index (index, index key and additional
filters to apply after index fetch

@param ctx
@param index
@param block
@param clazz

@return

given a full text index and a flat AND block returns a descriptor on how to process it with an index ( index index key and additional filters to apply after index fetch


private List<IndexSearchDescriptor> commonFactor(List<IndexSearchDescriptor> indexSearchDescriptors) {
    //index, key condition, additional filter (to aggregate in OR)
    Map<OIndex, Map<IndexCondPair, OOrBlock>> aggregation = new HashMap<>();
    for (IndexSearchDescriptor item : indexSearchDescriptors) {
      Map<IndexCondPair, OOrBlock> filtersForIndex = aggregation.get(item.idx);
      if (filtersForIndex == null) {
        filtersForIndex = new HashMap<>();
        aggregation.put(item.idx, filtersForIndex);
      }
      IndexCondPair extendedCond = new IndexCondPair(item.keyCondition, item.additionalRangeCondition);

      OOrBlock existingAdditionalConditions = filtersForIndex.get(extendedCond);
      if (existingAdditionalConditions == null) {
        existingAdditionalConditions = new OOrBlock(-1);
        filtersForIndex.put(extendedCond, existingAdditionalConditions);
      }
      existingAdditionalConditions.getSubBlocks().add(item.remainingCondition);
    }
    List<IndexSearchDescriptor> result = new ArrayList<>();
    for (Map.Entry<OIndex, Map<IndexCondPair, OOrBlock>> item : aggregation.entrySet()) {
      for (Map.Entry<IndexCondPair, OOrBlock> filters : item.getValue().entrySet()) {
        result.add(new IndexSearchDescriptor(item.getKey(), filters.getKey().mainCondition, filters.getKey().additionalRange,
            filters.getValue()));
      }
    }
    return result;
  }

aggregates multiple index conditions that refer to the same key search

@param indexSearchDescriptors

@return


public ODocumentFieldHandlingStrategy create(int strategy) {

    Optional<ODocumentFieldHandlingStrategy> registered = ODocumentFieldHandlingStrategyRegistry.getInstance()
        .getStrategy(strategy);
    if (registered.isPresent()) {
      return registered.get();
    }

    Map<OType, ODocumentFieldOTypeHandlingStrategy> typeHandlingStrategies = new HashMap<OType, ODocumentFieldOTypeHandlingStrategy>();

    switch (strategy) {
    case SINGLE_ORECORD_BYTES:
      typeHandlingStrategies.put(OType.BINARY, new ODocumentSingleRecordBytesOTypeHandlingStrategy());
      break;

    case SPLIT_ORECORD_BYTES:
      typeHandlingStrategies.put(OType.BINARY, new ODocumentSplitRecordBytesOTypeHandlingStrategy());
      break;

    case SIMPLE:
    default:
      break;
    }

    ODocumentSmartFieldHandlingStrategy strategyInstance = new ODocumentSmartFieldHandlingStrategy(typeHandlingStrategies);
    ODocumentFieldHandlingStrategyRegistry.getInstance().registerStrategy(strategy, strategyInstance);
    return strategyInstance;
  }

Creates a new instance of the requested strategy. Since strategies are stateless, if an existing instance already exists then
it's returned.

@param strategy
@return strategy instance

Creates a new instance of the requested strategy . Since strategies are stateless if an existing instance already exists then it s returned .


public ORole allow(final ORule.ResourceGeneric resourceGeneric, String resourceSpecific, final int iOperation) {
    if (roles == null || roles.isEmpty()) {
      if (document.field("roles") != null && !((Collection<OIdentifiable>) document.field("roles")).isEmpty()) {
        final ODocument doc = document;
        document = null;
        fromStream(doc);
      } else
        throw new OSecurityAccessException(document.getDatabase().getName(),
            "User '" + document.field("name") + "' has no role defined");
    }

    final ORole role = checkIfAllowed(resourceGeneric, resourceSpecific, iOperation);

    if (role == null)
      throw new OSecurityAccessException(document.getDatabase().getName(),
          "User '" + document.field("name") + "' does not have permission to execute the operation '" + ORole
              .permissionToString(iOperation) + "' against the resource: " + resourceGeneric + "." + resourceSpecific);

    return role;
  }

Checks if the user has the permission to access to the requested resource for the requested operation.

@param iOperation Requested operation

@return The role that has granted the permission if any, otherwise a OSecurityAccessException exception is raised

@throws OSecurityAccessException

Checks if the user has the permission to access to the requested resource for the requested operation .


public boolean isRuleDefined(final ORule.ResourceGeneric resourceGeneric, String resourceSpecific) {
    for (ORole r : roles)
      if (r == null)
        OLogManager.instance()
            .warn(this, "User '%s' has a null role, bypass it. Consider to fix this user roles before to continue", getName());
      else if (r.hasRule(resourceGeneric, resourceSpecific))
        return true;

    return false;
  }

Checks if a rule was defined for the user.

@return True is a rule is defined, otherwise false

Checks if a rule was defined for the user .


public static String getCompactServerStatus(final ODistributedServerManager manager, final ODocument distribCfg) {
    final StringBuilder buffer = new StringBuilder();

    final Collection<ODocument> members = distribCfg.field("members");

    if (members != null) {
      buffer.append(members.size());
      buffer.append(":[");

      int memberCount = 0;
      for (ODocument m : members) {
        if (m == null)
          continue;

        if (memberCount++ > 0)
          buffer.append(",");

        final String serverName = m.field("name");
        buffer.append(serverName);
        buffer.append((Object)m.field("status"));

        final Collection<String> databases = m.field("databases");
        if (databases != null) {
          buffer.append("{");
          int dbCount = 0;
          for (String dbName : databases) {
            final ODistributedConfiguration dbCfg = manager.getDatabaseConfiguration(dbName, false);

            if (dbCfg == null)
              continue;

            if (dbCount++ > 0)
              buffer.append(",");

            buffer.append(dbName);
            buffer.append("=");
            buffer.append(manager.getDatabaseStatus(serverName, dbName));
            buffer.append(" (");
            buffer.append(dbCfg.getServerRole(serverName));
            buffer.append(")");
          }
          buffer.append("}");
        }
      }
      buffer.append("]");
    }

    return buffer.toString();
  }

public
static
String
getCompactServerStatus
(
final
ODistributedServerManager
manager
,
final
ODocument
distribCfg
)
{
final
StringBuilder
buffer
=
new
StringBuilder
(
)
;
final
Collection
<
ODocument
>
members
=
distribCfg
.
field
(
"members"
)
;
if
(
members
!=
)
{
buffer
.
append
(
members
.
size
(
)
)
;
buffer
.
append
(
":["
)
;
int
memberCount
=
0
;
for
(
ODocument
m
:
members
)
{
if
(
m
==
)
continue
;
if
(
memberCount
++
>
0
)
buffer
.
append
(
","
)
;
final
String
serverName
=
m
.
field
(
"name"
)
;
buffer
.
append
(
serverName
)
;
buffer
.
append
(
(
Object
)
m
.
field
(
"status"
)
)
;
final
Collection
<
String
>
databases
=
m
.
field
(
"databases"
)
;
if
(
databases
!=
)
{
buffer
.
append
(
"{"
)
;
int
dbCount
=
0
;
for
(
String
dbName
:
databases
)
{
final
ODistributedConfiguration
dbCfg
=
manager
.
getDatabaseConfiguration
(
dbName
,
false
)
;
if
(
dbCfg
==
)
continue
;
if
(
dbCount
++
>
0
)
buffer
.
append
(
","
)
;
buffer
.
append
(
dbName
)
;
buffer
.
append
(
"="
)
;
buffer
.
append
(
manager
.
getDatabaseStatus
(
serverName
,
dbName
)
)
;
buffer
.
append
(
" ("
)
;
buffer
.
append
(
dbCfg
.
getServerRole
(
serverName
)
)
;
buffer
.
append
(
")"
)
;
}
buffer
.
append
(
"}"
)
;
}
}
buffer
.
append
(
"]"
)
;
}
return
buffer
.
toString
(
)
;
}

Create a compact string with all the relevant information.

@param manager
@param distribCfg

@return

Create a compact string with all the relevant information .


protected void initSystemDatabase() {
    final ODocument defaultCfg = getStorage(OSystemDatabase.SYSTEM_DB_NAME)
        .loadDatabaseConfiguration(getDefaultDatabaseConfigFile());
    defaultCfg.field("autoDeploy", false);
    final OModifiableDistributedConfiguration sysCfg = new OModifiableDistributedConfiguration(defaultCfg);
    sysCfg.removeServer("<NEW_NODE>");

    messageService.registerDatabase(OSystemDatabase.SYSTEM_DB_NAME, sysCfg);
    sysCfg.addNewNodeInServerList(getLocalNodeName());
  }

protected void initSystemDatabase ( ) { final ODocument defaultCfg = getStorage ( OSystemDatabase . SYSTEM_DB_NAME ) . loadDatabaseConfiguration ( getDefaultDatabaseConfigFile ( ) ) ; defaultCfg . field ( "autoDeploy" , false ) ; final OModifiableDistributedConfiguration sysCfg = new OModifiableDistributedConfiguration ( defaultCfg ) ; sysCfg . removeServer ( "<NEW_NODE>" ) ; messageService . registerDatabase ( OSystemDatabase . SYSTEM_DB_NAME , sysCfg ) ; sysCfg . addNewNodeInServerList ( getLocalNodeName ( ) ) ; }

Protecte system database from being replicated


protected void loadLocalDatabases() {
    final List<String> dbs = new ArrayList<String>(serverInstance.getAvailableStorageNames().keySet());
    Collections.sort(dbs);

    for (final String databaseName : dbs) {
      if (messageService.getDatabase(databaseName) == null) {
        ODistributedServerLog.info(this, nodeName, null, DIRECTION.NONE, "Opening database '%s'...", databaseName);

        // INIT THE STORAGE
        final ODistributedStorage stg = getStorage(databaseName);

        executeInDistributedDatabaseLock(databaseName, 60000, null, new OCallable<Object, OModifiableDistributedConfiguration>() {
          @Override
          public Object call(OModifiableDistributedConfiguration cfg) {
            ODistributedServerLog.info(this, nodeName, null, DIRECTION.NONE, "Current node started as %s for database '%s'",
                cfg.getServerRole(nodeName), databaseName);

            final ODistributedDatabaseImpl ddb = messageService.registerDatabase(databaseName, cfg);
            ddb.resume();

            // 1ST NODE TO HAVE THE DATABASE
            cfg.addNewNodeInServerList(nodeName);

            // COLLECT ALL THE CLUSTERS WITH REMOVED NODE AS OWNER
            reassignClustersOwnership(nodeName, databaseName, cfg, true);

            try {
              ddb.getSyncConfiguration().setLastLSN(nodeName, ((OAbstractPaginatedStorage) stg.getUnderlying()).getLSN(), false);
            } catch (IOException e) {
              ODistributedServerLog
                  .error(this, nodeName, null, DIRECTION.NONE, "Error on saving distributed LSN for database '%s' (err=%s).",
                      databaseName, e.getMessage());
            }
            ddb.setOnline();

            return null;
          }
        });
      }
    }
  }

Initializes all the available server's databases as distributed.

Initializes all the available server s databases as distributed .


@Override
  public void memberRemoved(final MembershipEvent iEvent) {
    try {
      updateLastClusterChange();

      if (iEvent.getMember() == null)
        return;

      final String nodeLeftName = getNodeName(iEvent.getMember());
      if (nodeLeftName == null)
        return;

      removeServer(nodeLeftName, true);

    } catch (HazelcastInstanceNotActiveException | RetryableHazelcastException e) {
      OLogManager.instance().error(this, "Hazelcast is not running", e);
    } catch (Exception e) {
      OLogManager.instance().error(this, "Error on removing the server '%s'", e, getNodeName(iEvent.getMember()));
    }
  }

@
Override
public
void
memberRemoved
(
final
MembershipEvent
iEvent
)
{
try
{
updateLastClusterChange
(
)
;
if
(
iEvent
.
getMember
(
)
==
)
return
;
final
String
nodeLeftName
=
getNodeName
(
iEvent
.
getMember
(
)
)
;
if
(
nodeLeftName
==
)
return
;
removeServer
(
nodeLeftName
,
true
)
;
}
catch
(
HazelcastInstanceNotActiveException
|
RetryableHazelcastException
e
)
{
OLogManager
.
instance
(
)
.
error
(
this
,
"Hazelcast is not running"
,
e
)
;
}
catch
(
Exception
e
)
{
OLogManager
.
instance
(
)
.
error
(
this
,
"Error on removing the server '%s'"
,
e
,
getNodeName
(
iEvent
.
getMember
(
)
)
)
;
}
}


@Override
  public String electNewLockManager() {
    if (hazelcastInstance == null)
      throw new HazelcastInstanceNotActiveException();

    final ILock lock = hazelcastInstance.getLock("orientdb.lockManagerElection");
    lock.lock();
    try {

      // TRY ALL THE SERVERS IN ORDER (ALL THE SERVERS HAVE THE SAME LIST)
      String lockManagerServer = getLockManagerRequester().getServer();

      // PROTECT FROM DOUBLE LOCK MANAGER ELECTION IN CASE OF REMOVE OF LOCK MANAGER
      if (lockManagerServer != null && getActiveServers().contains(lockManagerServer))
        return lockManagerServer;

      final String originalLockManager = lockManagerServer;

      ODistributedServerLog
          .debug(this, nodeName, originalLockManager, DIRECTION.OUT, "lock '%s' is unreachable, electing a new lock...",
              originalLockManager);

      int lockManagerServerId = -1;
      if (lockManagerServer != null && registeredNodeByName.containsKey(lockManagerServer))
        lockManagerServerId = registeredNodeByName.get(lockManagerServer);

      String newServer = null;

      int currIndex = lockManagerServerId;
      for (int i = 0; i < registeredNodeById.size(); ++i) {
        currIndex++;
        if (currIndex >= registeredNodeById.size())
          // RESTART FROM THE FIRST
          currIndex = 0;

        newServer = registeredNodeById.get(currIndex);
        if (newServer == null)
          throw new OConfigurationException("Found null server at index " + currIndex + " of server list " + registeredNodeById);

        if (newServer.equalsIgnoreCase(getLocalNodeName()) || activeNodes.containsKey(newServer)) {
          // TODO: IMPROVE ELECTION BY CHECKING AL THE NODES AGREE ON IT

          ODistributedServerLog
              .debug(this, nodeName, newServer, DIRECTION.OUT, "Trying to elected server '%s' as new lock (old=%s)...", newServer,
                  originalLockManager);

          try {
            getLockManagerRequester().setServer(newServer);

            configurationMap.put(CONFIG_LOCKMANAGER, getLockManagerRequester().getServer());

            ODistributedServerLog
                .info(this, nodeName, newServer, DIRECTION.OUT, "Elected server '%s' as new lock (old=%s)", newServer,
                    originalLockManager);

            break;

          } catch (Exception e) {
            // NO SERVER RESPONDED, THE SERVER COULD BE ISOLATED, GO AHEAD WITH THE NEXT IN THE LIST
            ODistributedServerLog
                .info(this, nodeName, newServer, DIRECTION.OUT, "Error on electing server '%s' as new lock (error: %s)", newServer,
                    e);
          }
        }
      }

      return newServer;

    } finally {
      lock.unlock();
    }
  }

Elects a new server as coordinator. The election browse the ordered server list.

Elects a new server as coordinator . The election browse the ordered server list .


private void assignLockManagerFromCluster() {
    String lockManagerServer = null;
    while (lockManagerServer == null) {
      if (activeNodes.size() == 1) {
        // ONLY CURRENT NODE ONLINE, SET IT AS INITIAL LOCK MANAGER
        lockManagerServer = nodeName;
        if (configurationMap.putIfAbsent(CONFIG_LOCKMANAGER, lockManagerServer) == null)
          break;
      } else {
        lockManagerServer = (String) configurationMap.get(CONFIG_LOCKMANAGER);

        if (lockManagerServer != null && lockManagerServer.equals(nodeName)) {
          // LAST LOCK MANAGER WAS CURRENT NODE? TRY TO FORCE A NEW ELECTION
          OLogManager.instance().info(this, "Found lock as current node, even if it was offline. Forcing a new election...");
          getLockManagerRequester().setServer(lockManagerServer);
          lockManagerServer = electNewLockManager();
          break;
        }

        if (lockManagerServer != null)
          break;
      }

      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        break;
      }
    }

    getLockManagerRequester().setServer(lockManagerServer);

    OLogManager.instance().info(this, "Distributed Lock Manager server is '%s'", lockManagerServer);
  }


public void commit() {
    if (!active)
      throw error("Inactive micro-transaction on commit");
    if (level < 1)
      throw error("Unbalanced micro-transaction, level = " + level);

    --level;

    if (level == 0) {
      active = false;
      doCommit();
    }
  }

Commits the micro-transaction if it's a top-level micro-transaction.

Commits the micro - transaction if it s a top - level micro - transaction .


public void rollback() {
    if (!active)
      throw error("Inactive micro-transaction on rollback");
    if (level < 1)
      throw error("Unbalanced micro-transaction, level = " + level);

    --level;

    if (level == 0) {
      active = false;
      doRollback();
    }
  }

Rollbacks the micro-transaction if it's a top-level micro-transaction.

Rollbacks the micro - transaction if it s a top - level micro - transaction .


public void updateIdentityAfterRecordCommit(final ORID oldRid, final ORID newRid) {
    if (oldRid.equals(newRid))
      return; // no change, ignore

    // XXX: Identity update may mutate the index keys, so we have to identify and reinsert potentially affected index keys to keep
    // the OTransactionIndexChanges.changesPerKey in a consistent state.

    final List<KeyChangesUpdateRecord> keyRecordsToReinsert = new ArrayList<>();
    final OIndexManager indexManager = getDatabase().getMetadata().getIndexManager();
    for (Map.Entry<String, OTransactionIndexChanges> entry : indexOperations.entrySet()) {
      final OIndex<?> index = indexManager.getIndex(entry.getKey());
      if (index == null)
        throw new OTransactionException("Cannot find index '" + entry.getValue() + "' while committing transaction");

      final Dependency[] fieldRidDependencies = getIndexFieldRidDependencies(index);
      if (!isIndexMayDependOnRids(fieldRidDependencies))
        continue;

      final OTransactionIndexChanges indexChanges = entry.getValue();
      for (final Iterator<OTransactionIndexChangesPerKey> iterator = indexChanges.changesPerKey.values().iterator(); iterator
          .hasNext(); ) {
        final OTransactionIndexChangesPerKey keyChanges = iterator.next();
        if (isIndexKeyMayDependOnRid(keyChanges.key, oldRid, fieldRidDependencies)) {
          keyRecordsToReinsert.add(new KeyChangesUpdateRecord(keyChanges, indexChanges));
          iterator.remove();
        }
      }
    }

    // Update the identity.

    final ORecordOperation rec = resolveRecordOperation(oldRid);
    if (rec != null) {
      updatedRids.put(newRid.copy(), oldRid.copy());

      if (!rec.getRecord().getIdentity().equals(newRid)) {
        ORecordInternal.onBeforeIdentityChanged(rec.getRecord());

        final ORecordId recordId = (ORecordId) rec.getRecord().getIdentity();
        if (recordId == null) {
          ORecordInternal.setIdentity(rec.getRecord(), new ORecordId(newRid));
        } else {
          recordId.setClusterPosition(newRid.getClusterPosition());
          recordId.setClusterId(newRid.getClusterId());
        }

        ORecordInternal.onAfterIdentityChanged(rec.getRecord());
      }
    }

    // Reinsert the potentially affected index keys.

    for (KeyChangesUpdateRecord record : keyRecordsToReinsert)
      record.indexChanges.changesPerKey.put(record.keyChanges.key, record.keyChanges);

    // Update the indexes.

    final List<OTransactionRecordIndexOperation> transactionIndexOperations = recordIndexOperations.get(translateRid(oldRid));
    if (transactionIndexOperations != null) {
      for (final OTransactionRecordIndexOperation indexOperation : transactionIndexOperations) {
        OTransactionIndexChanges indexEntryChanges = indexOperations.get(indexOperation.index);
        if (indexEntryChanges == null)
          continue;
        final OTransactionIndexChangesPerKey keyChanges;
        if (indexOperation.key == null) {
          keyChanges = indexEntryChanges.nullKeyChanges;
        } else {
          keyChanges = indexEntryChanges.changesPerKey.get(indexOperation.key);
        }
        if (keyChanges != null)
          updateChangesIdentity(oldRid, newRid, keyChanges);
      }
    }
  }

Updates the record identity after its successful commit.

Updates the record identity after its successful commit .


public void updateRecordCacheAfterRollback() {
    final OLocalRecordCache databaseLocalCache = database.getLocalCache();

    for (ORecordOperation recordOperation : recordOperations.values())
      databaseLocalCache.deleteRecord(recordOperation.getRecord().getIdentity());
  }

public void updateRecordCacheAfterRollback ( ) { final OLocalRecordCache databaseLocalCache = database . getLocalCache ( ) ; for ( ORecordOperation recordOperation : recordOperations . values ( ) ) databaseLocalCache . deleteRecord ( recordOperation . getRecord ( ) . getIdentity ( ) ) ; }

Updates the record cache after unsuccessful micro-transaction commit.

Updates the record cache after unsuccessful micro - transaction commit .


public static void prepareForFileCreationOrReplacement(Path path, Object requester, String operation) throws IOException {
    if (Files.deleteIfExists(path))
      OLogManager.instance().warn(requester, "'%s' deleted while %s", path, operation);

    final Path parent = path.getParent();
    if (parent != null)
      Files.createDirectories(parent);
  }

public
static
void
prepareForFileCreationOrReplacement
(
Path
path
,
Object
requester
,
String
operation
)
throws
IOException
{
if
(
Files
.
deleteIfExists
(
path
)
)
OLogManager
.
instance
(
)
.
warn
(
requester
,
"'%s' deleted while %s"
,
path
,
operation
)
;
final
Path
parent
=
path
.
getParent
(
)
;
if
(
parent
!=
)
Files
.
createDirectories
(
parent
)
;
}

Prepares the path for a file creation or replacement. If the file pointed by the path already exists, it will be deleted, a
warning will be emitted to the log in this case. All absent directories along the path will be created.

@param path      the file path.
@param requester the requester of an operation being performed to produce user-friendly log messages.
@param operation the description of an operation being performed to produce user-friendly log messages. Use descriptions like
"exporting", "backing up", etc.

Prepares the path for a file creation or replacement . If the file pointed by the path already exists it will be deleted a warning will be emitted to the log in this case . All absent directories along the path will be created .


public static void atomicMoveWithFallback(Path source, Path target, Object requester) throws IOException {
    try {
      Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
    } catch (AtomicMoveNotSupportedException ignore) {
      OLogManager.instance()
          .warn(requester, "atomic file move is not possible, falling back to regular move (moving '%s' to '%s')", source, target);
      Files.move(source, target);
    }
  }

Tries to move a file from the source to the target atomically. If atomic move is not possible, falls back to regular move.

@param source    the source to move the file from.
@param target    the target to move the file to.
@param requester the requester of the move being performed to produce user-friendly log messages.

@see Files#move(Path, Path, CopyOption...)
@see StandardCopyOption#ATOMIC_MOVE

Tries to move a file from the source to the target atomically . If atomic move is not possible falls back to regular move .


public List<Pattern> getDisjointPatterns() {
    Map<PatternNode, String> reverseMap = new IdentityHashMap<>();
    reverseMap.putAll(this.aliasToNode.entrySet().stream().collect(Collectors.toMap(x -> x.getValue(), x -> x.getKey())));

    List<Pattern> result = new ArrayList<>();
    while (!reverseMap.isEmpty()) {
      Pattern pattern = new Pattern();
      result.add(pattern);
      Map.Entry<PatternNode, String> nextNode = reverseMap.entrySet().iterator().next();
      Set<PatternNode> toVisit = new HashSet<>();
      toVisit.add(nextNode.getKey());
      while (toVisit.size() > 0) {
        PatternNode currentNode = toVisit.iterator().next();
        toVisit.remove(currentNode);
        if (reverseMap.containsKey(currentNode)) {
          pattern.aliasToNode.put(reverseMap.get(currentNode), currentNode);
          reverseMap.remove(currentNode);
          for (PatternEdge x : currentNode.out) {
            toVisit.add(x.in);
          }
          for (PatternEdge x : currentNode.in) {
            toVisit.add(x.out);
          }
        }
      }
      pattern.recalculateNumOfEdges();
    }
    return result;
  }

public List < Pattern > getDisjointPatterns ( ) { Map < PatternNode , String > reverseMap = new IdentityHashMap <> ( ) ; reverseMap . putAll ( this . aliasToNode . entrySet ( ) . stream ( ) . collect ( Collectors . toMap ( x -> x . getValue ( ) , x -> x . getKey ( ) ) ) ) ; List < Pattern > result = new ArrayList <> ( ) ; while ( ! reverseMap . isEmpty ( ) ) { Pattern pattern = new Pattern ( ) ; result . add ( pattern ) ; Map . Entry < PatternNode , String > nextNode = reverseMap . entrySet ( ) . iterator ( ) . next ( ) ; Set < PatternNode > toVisit = new HashSet <> ( ) ; toVisit . add ( nextNode . getKey ( ) ) ; while ( toVisit . size ( ) > 0 ) { PatternNode currentNode = toVisit . iterator ( ) . next ( ) ; toVisit . remove ( currentNode ) ; if ( reverseMap . containsKey ( currentNode ) ) { pattern . aliasToNode . put ( reverseMap . get ( currentNode ) , currentNode ) ; reverseMap . remove ( currentNode ) ; for ( PatternEdge x : currentNode . out ) { toVisit . add ( x . in ) ; } for ( PatternEdge x : currentNode . in ) { toVisit . add ( x . out ) ; } } } pattern . recalculateNumOfEdges ( ) ; } return result ; }

splits this pattern into multiple

@return


protected boolean executeOnlyLocally(final String localNodeName, final ODistributedConfiguration dbCfg,
      final OCommandExecutor exec, final Collection<String> involvedClusters, final Collection<String> nodes) {
    boolean executeLocally = false;
    if (exec.isIdempotent()) {
      final int availableNodes = nodes.size();

      // IDEMPOTENT: CHECK IF CAN WORK LOCALLY ONLY
      int maxReadQuorum;
      if (involvedClusters.isEmpty())
        maxReadQuorum = dbCfg.getReadQuorum(null, availableNodes, localNodeName);
      else {
        maxReadQuorum = 0;
        for (String cl : involvedClusters)
          maxReadQuorum = Math.max(maxReadQuorum, dbCfg.getReadQuorum(cl, availableNodes, localNodeName));
      }

      if (nodes.contains(localNodeName) && maxReadQuorum <= 1)
        executeLocally = true;
    }

    return executeLocally;
  }

  public boolean isLocalEnv() {
    return localDistributedDatabase == null || dManager == null || distributedConfiguration == null || OScenarioThreadLocal.INSTANCE
        .isRunModeDistributed();
  }

  public OStorageOperationResult<ORawBuffer> readRecord(final ORecordId iRecordId, final String iFetchPlan,
      final boolean iIgnoreCache, final boolean prefetchRecords, final ORecordCallback<ORawBuffer> iCallback) {

    if (isLocalEnv()) {
      // ALREADY DISTRIBUTED
      return wrapped.readRecord(iRecordId, iFetchPlan, iIgnoreCache, prefetchRecords, iCallback);
    }

    final ORawBuffer memCopy = localDistributedDatabase.getRecordIfLocked(iRecordId);
    if (memCopy != null)
      return new OStorageOperationResult<ORawBuffer>(memCopy);

    try {
      final String clusterName = getClusterNameByRID(iRecordId);

      final ODistributedConfiguration dbCfg = distributedConfiguration;
      final List<String> nodes = dbCfg.getServers(clusterName, null);
      final int availableNodes = nodes.size();

      // CHECK IF LOCAL NODE OWNS THE DATA AND READ-QUORUM = 1: GET IT LOCALLY BECAUSE IT'S FASTER
      final String localNodeName = dManager.getLocalNodeName();

      if (nodes.isEmpty()
          || nodes.contains(dManager.getLocalNodeName()) && dbCfg.getReadQuorum(clusterName, availableNodes, localNodeName) <= 1) {
        // DON'T REPLICATE
        return (OStorageOperationResult<ORawBuffer>) OScenarioThreadLocal.executeAsDistributed(new Callable() {
          @Override
          public Object call() throws Exception {
            return wrapped.readRecord(iRecordId, iFetchPlan, iIgnoreCache, prefetchRecords, iCallback);
          }
        });
      }

      final OReadRecordTask task = ((OReadRecordTask) dManager.getTaskFactoryManager().getFactoryByServerNames(nodes)
          .createTask(OReadRecordTask.FACTORYID)).init(iRecordId);

      // DISTRIBUTE IT
      final ODistributedResponse response = dManager
          .sendRequest(getName(), Collections.singleton(clusterName), nodes, task, dManager.getNextMessageIdCounter(),
              EXECUTION_MODE.RESPONSE, null, null, null);
      final Object dResult = response != null ? response.getPayload() : null;

      if (dResult instanceof ONeedRetryException)
        throw (ONeedRetryException) dResult;
      else if (dResult instanceof Exception)
        throw OException
            .wrapException(new ODistributedException("Error on execution distributed read record"), (Exception) dResult);

      return new OStorageOperationResult<ORawBuffer>((ORawBuffer) dResult);

    } catch (ONeedRetryException e) {
      // PASS THROUGH
      throw e;
    } catch (Exception e) {
      handleDistributedException("Cannot route read record operation for %s to the distributed node", e, iRecordId);
      // UNREACHABLE
      return null;
    }
  }

  @Override
  public OStorageOperationResult<ORawBuffer> readRecordIfVersionIsNotLatest(final ORecordId rid, final String fetchPlan,
      final boolean ignoreCache, final int recordVersion) throws ORecordNotFoundException {
    if (isLocalEnv()) {
      return wrapped.readRecordIfVersionIsNotLatest(rid, fetchPlan, ignoreCache, recordVersion);
    }
    final ORawBuffer memCopy = localDistributedDatabase.getRecordIfLocked(rid);
    if (memCopy != null)
      return new OStorageOperationResult<ORawBuffer>(memCopy);

    try {
      final String clusterName = getClusterNameByRID(rid);

      final ODistributedConfiguration dbCfg = distributedConfiguration;
      final List<String> nodes = dbCfg.getServers(clusterName, null);
      final int availableNodes = nodes.size();

      // CHECK IF LOCAL NODE OWNS THE DATA AND READ-QUORUM = 1: GET IT LOCALLY BECAUSE IT'S FASTER
      final String localNodeName = dManager.getLocalNodeName();

      if (nodes.isEmpty()
          || nodes.contains(dManager.getLocalNodeName()) && dbCfg.getReadQuorum(clusterName, availableNodes, localNodeName) <= 1) {
        // DON'T REPLICATE
        return (OStorageOperationResult<ORawBuffer>) OScenarioThreadLocal.executeAsDistributed(new Callable() {
          @Override
          public Object call() throws Exception {
            return wrapped.readRecordIfVersionIsNotLatest(rid, fetchPlan, ignoreCache, recordVersion);
          }
        });
      }

      final OReadRecordIfNotLatestTask task = (OReadRecordIfNotLatestTask) dManager.getTaskFactoryManager()
          .getFactoryByServerNames(nodes).createTask(OReadRecordIfNotLatestTask.FACTORYID);
      task.init(rid, recordVersion);

      // DISTRIBUTE IT
      final Object result = dManager
          .sendRequest(getName(), Collections.singleton(clusterName), nodes, task, dManager.getNextMessageIdCounter(),
              EXECUTION_MODE.RESPONSE, null, null, null).getPayload();

      if (result instanceof ONeedRetryException)
        throw (ONeedRetryException) result;
      else if (result instanceof Exception)
        throw OException.wrapException(new ODistributedException("Error on execution distributed read record"), (Exception) result);

      return new OStorageOperationResult<ORawBuffer>((ORawBuffer) result);

    } catch (ONeedRetryException e) {
      // PASS THROUGH
      throw e;
    } catch (Exception e) {
      handleDistributedException("Cannot route read record operation for %s to the distributed node", e, rid);
      // UNREACHABLE
      return null;
    }
  }

  @Override
  public OStorageOperationResult<Boolean> deleteRecord(final ORecordId iRecordId, final int iVersion, final int iMode,
      final ORecordCallback<Boolean> iCallback) {
    // IF is a real delete should be with a tx
    return wrapped.deleteRecord(iRecordId, iVersion, iMode, iCallback);
  }

Only idempotent commands that don't involve any other node can be executed locally.

Only idempotent commands that don t involve any other node can be executed locally .


@Override
  public void characters(char[] ch, int start, int length) throws SAXException {
    builder.append(ch, start, length);
  }

@ Override public void characters ( char [ ] ch , int start , int length ) throws SAXException { builder . append ( ch , start , length ) ; }

Collect up the characters, as element's characters may be split across multiple calls. Isn't SAX lovely...

Collect up the characters as element s characters may be split across multiple calls . Isn t SAX lovely ...


public boolean isConnected() {
    final Socket s = socket;
    return s != null && !s.isClosed() && s.isConnected() && !s.isInputShutdown() && !s.isOutputShutdown();
  }

public boolean isConnected ( ) { final Socket s = socket ; return s != null && ! s . isClosed ( ) && s . isConnected ( ) && ! s . isInputShutdown ( ) && ! s . isOutputShutdown ( ) ; }

Tells if the channel is connected.

@return true if it's connected, otherwise false.


public static short mergeShortFromBuffers(final ByteBuffer buffer, final ByteBuffer buffer1) {
    short result = 0;
    result = (short) (result | (buffer.get() & MASK));
    result = (short) (result << SIZE_OF_BYTE_IN_BITS);
    result = (short) (result | (buffer1.get() & MASK));
    return result;
  }

public static short mergeShortFromBuffers ( final ByteBuffer buffer , final ByteBuffer buffer1 ) { short result = 0 ; result = ( short ) ( result | ( buffer . get ( ) & MASK ) ) ; result = ( short ) ( result << SIZE_OF_BYTE_IN_BITS ) ; result = ( short ) ( result | ( buffer1 . get ( ) & MASK ) ) ; return result ; }

Merge short value from two byte buffer. First byte of short will be extracted from first byte buffer and second from second
one.

@param buffer
to read first part of value
@param buffer1
to read second part of value
@return merged value

Merge short value from two byte buffer . First byte of short will be extracted from first byte buffer and second from second one .


public static void splitShortToBuffers(final ByteBuffer buffer, final ByteBuffer buffer1, final short iValue) {
    buffer.put((byte) (MASK & (iValue >>> SIZE_OF_BYTE_IN_BITS)));
    buffer1.put((byte) (MASK & iValue));
  }

public static void splitShortToBuffers ( final ByteBuffer buffer , final ByteBuffer buffer1 , final short iValue ) { buffer . put ( ( byte ) ( MASK & ( iValue >>> SIZE_OF_BYTE_IN_BITS ) ) ) ; buffer1 . put ( ( byte ) ( MASK & iValue ) ) ; }

Split short value into two byte buffer. First byte of short will be written to first byte buffer and second to second one.

@param buffer
to write first part of value
@param buffer1
to write second part of value

Split short value into two byte buffer . First byte of short will be written to first byte buffer and second to second one .


public Object execute(final Map<Object, Object> iArgs) {
    if (type == null)
      throw new OCommandExecutionException("Cannot execute the command because it has not been parsed yet");

    final ODatabaseDocument database = getDatabase();
    final OClassEmbedded sourceClass = (OClassEmbedded) database.getMetadata().getSchema().getClass(className);
    if (sourceClass == null)
      throw new OCommandExecutionException("Source class '" + className + "' not found");

    OPropertyImpl prop = (OPropertyImpl) sourceClass.getProperty(fieldName);

    if (prop != null) {
      if (ifNotExists) {
        return sourceClass.properties().size();
      }
      throw new OCommandExecutionException(
          "Property '" + className + "." + fieldName + "' already exists. Remove it before to retry.");
    }

    // CREATE THE PROPERTY
    OClass linkedClass = null;
    OType linkedType = null;
    if (linked != null) {
      // FIRST SEARCH BETWEEN CLASSES
      linkedClass = database.getMetadata().getSchema().getClass(linked);

      if (linkedClass == null)
        // NOT FOUND: SEARCH BETWEEN TYPES
        linkedType = OType.valueOf(linked.toUpperCase(Locale.ENGLISH));
    }

    // CREATE IT LOCALLY
    OPropertyImpl internalProp = sourceClass.addPropertyInternal(fieldName, type, linkedType, linkedClass, unsafe);
    if (readonly) {
      internalProp.setReadonly(true);
    }

    if (mandatory) {
      internalProp.setMandatory(true);
    }

    if (notnull) {
      internalProp.setNotNull(true);
    }

    if (max != null) {
      internalProp.setMax(max);
    }

    if (min != null) {
      internalProp.setMin(min);
    }

    if (defaultValue != null) {
      internalProp.setDefaultValue(defaultValue);
    }

    return sourceClass.properties().size();
  }


@Override
  public OIndexFullText put(Object key, final OIdentifiable singleValue) {
    if (key == null) {
      return this;
    }

    key = getCollatingValue(key);

    final Set<String> words = splitIntoWords(key.toString());

    // FOREACH WORD CREATE THE LINK TO THE CURRENT DOCUMENT
    for (final String word : words) {
      acquireSharedLock();
      try {
        if (apiVersion == 0) {
          doPutV0(singleValue, word);
        } else if (apiVersion == 1) {
          doPutV1(singleValue, word);
        } else {
          throw new IllegalStateException("Invalid API version, " + apiVersion);
        }

      } finally {
        releaseSharedLock();
      }
    }

    return this;
  }

Indexes a value and save the index. Splits the value in single words and index each one. Save of the index is responsibility of
the caller.

Indexes a value and save the index . Splits the value in single words and index each one . Save of the index is responsibility of the caller .


@Override
  public boolean remove(Object key, final OIdentifiable value) {
    if (key == null) {
      return false;
    }

    key = getCollatingValue(key);

    final Set<String> words = splitIntoWords(key.toString());
    final OModifiableBoolean removed = new OModifiableBoolean(false);

    for (final String word : words) {
      acquireSharedLock();
      try {
        if (apiVersion == 0) {
          removeV0(value, removed, word);
        } else if (apiVersion == 1) {
          removeV1(value, removed, word);
        } else {
          throw new IllegalStateException("Invalid API version, " + apiVersion);
        }
      } finally {
        releaseSharedLock();
      }
    }

    return removed.getValue();
  }

@
Override
public
boolean
remove
(
Object
key
,
final
OIdentifiable
value
)
{
if
(
key
==
)
{
return
false
;
}
key
=
getCollatingValue
(
key
)
;
final
Set
<
String
>
words
=
splitIntoWords
(
key
.
toString
(
)
)
;
final
OModifiableBoolean
removed
=
new
OModifiableBoolean
(
false
)
;
for
(
final
String
word
:
words
)
{
acquireSharedLock
(
)
;
try
{
if
(
apiVersion
==
0
)
{
removeV0
(
value
,
removed
,
word
)
;
}
else
if
(
apiVersion
==
1
)
{
removeV1
(
value
,
removed
,
word
)
;
}
else
{
throw
new
IllegalStateException
(
"Invalid API version, "
+
apiVersion
)
;
}
}
finally
{
releaseSharedLock
(
)
;
}
}
return
removed
.
getValue
(
)
;
}

Splits passed in key on several words and remove records with keys equals to any item of split result and values equals to
passed in value.

@param key   Key to remove.
@param value Value to remove.

@return true if at least one record is removed.

Splits passed in key on several words and remove records with keys equals to any item of split result and values equals to passed in value .


@SuppressWarnings("unchecked")
  public List<T> run(final Object... iArgs) {
    final ODatabaseDocumentInternal database = ODatabaseRecordThreadLocal.instance().get();
    if (database == null)
      throw new OQueryParsingException("No database configured");

    ((OMetadataInternal) database.getMetadata()).makeThreadLocalSchemaSnapshot();
    try {
      setParameters(iArgs);
      Object o = database.getStorage().command(this);
      if (o instanceof List) {
        return (List<T>) o;
      } else {
        return (List<T>) Collections.singletonList(o);
      }

    } finally {
      ((OMetadataInternal) database.getMetadata()).clearThreadLocalSchemaSnapshot();
    }
  }

@
SuppressWarnings
(
"unchecked"
)
public
List
<
T
>
run
(
final
Object
...
iArgs
)
{
final
ODatabaseDocumentInternal
database
=
ODatabaseRecordThreadLocal
.
instance
(
)
.
get
(
)
;
if
(
database
==
)
throw
new
OQueryParsingException
(
"No database configured"
)
;
(
(
OMetadataInternal
)
database
.
getMetadata
(
)
)
.
makeThreadLocalSchemaSnapshot
(
)
;
try
{
setParameters
(
iArgs
)
;
Object
o
=
database
.
getStorage
(
)
.
command
(
this
)
;
if
(
o
instanceof
List
)
{
return
(
List
<
T
>
)
o
;
}
else
{
return
(
List
<
T
>
)
Collections
.
singletonList
(
o
)
;
}
}
finally
{
(
(
OMetadataInternal
)
database
.
getMetadata
(
)
)
.
clearThreadLocalSchemaSnapshot
(
)
;
}
}

Delegates to the OQueryExecutor the query execution.

Delegates to the OQueryExecutor the query execution .


public T runFirst(final Object... iArgs) {
    setLimit(1);
    final List<T> result = execute(iArgs);
    return result != null && !result.isEmpty() ? result.get(0) : null;
  }

public T runFirst ( final Object ... iArgs ) { setLimit ( 1 ) ; final List < T > result = execute ( iArgs ) ; return result != null && ! result . isEmpty ( ) ? result . get ( 0 ) : null ; }


public void create() throws IOException {
    acquireWriteLock();
    try {
      acquireExclusiveAccess();

      openChannel();
      init();

      setVersion(OFileClassic.CURRENT_VERSION);
      version = OFileClassic.CURRENT_VERSION;

      initAllocationMode();
    } finally {
      releaseWriteLock();
    }
  }

public void create ( ) throws IOException { acquireWriteLock ( ) ; try { acquireExclusiveAccess ( ) ; openChannel ( ) ; init ( ) ; setVersion ( OFileClassic . CURRENT_VERSION ) ; version = OFileClassic . CURRENT_VERSION ; initAllocationMode ( ) ; } finally { releaseWriteLock ( ) ; } }


private long checkRegions(final long iOffset, final long iLength) {
    acquireReadLock();
    try {
      if (iOffset < 0 || iOffset + iLength > size) {
        throw new OIOException(
            "You cannot access outside the file size (" + size + " bytes). You have requested portion " + iOffset + "-" + (iOffset
                + iLength) + " bytes. File: " + this);
      }

      return iOffset + HEADER_SIZE;
    } finally {
      releaseReadLock();
    }

  }

ALWAYS ADD THE HEADER SIZE BECAUSE ON THIS TYPE IS ALWAYS NEEDED


public void replaceContentWith(final Path newContentFile) throws IOException {
    acquireWriteLock();
    try {
      close();

      Files.copy(newContentFile, osFile, StandardCopyOption.REPLACE_EXISTING);

      open();
    } finally {
      releaseWriteLock();
    }
  }

public void replaceContentWith ( final Path newContentFile ) throws IOException { acquireWriteLock ( ) ; try { close ( ) ; Files . copy ( newContentFile , osFile , StandardCopyOption . REPLACE_EXISTING ) ; open ( ) ; } finally { releaseWriteLock ( ) ; } }

Replaces the file content with the content of the provided file.

@param newContentFile the new content file to replace the content with.

Replaces the file content with the content of the provided file .


public Object command(final OCommandRequestText iCommand) {

    final boolean live = iCommand instanceof OLiveQuery;
    final ODatabaseDocumentInternal database = ODatabaseRecordThreadLocal.instance().get();
    final boolean asynch = iCommand instanceof OCommandRequestAsynch && ((OCommandRequestAsynch) iCommand).isAsynchronous();

    OCommandRequest request = new OCommandRequest(database, asynch, iCommand, live);
    OCommandResponse response = networkOperation(request, "Error on executing command: " + iCommand);
    return response.getResult();

  }

public
Object
command
(
final
OCommandRequestText
iCommand
)
{
final
boolean
live
=
iCommand
instanceof
OLiveQuery
;
final
ODatabaseDocumentInternal
database
=
ODatabaseRecordThreadLocal
.
instance
(
)
.
get
(
)
;
final
boolean
asynch
=
iCommand
instanceof
OCommandRequestAsynch
&&
(
(
OCommandRequestAsynch
)
iCommand
)
.
isAsynchronous
(
)
;
OCommandRequest
request
=
new
OCommandRequest
(
database
,
asynch
,
iCommand
,
live
)
;
OCommandResponse
response
=
networkOperation
(
request
,
"Error on executing command: "
+
iCommand
)
;
return
response
.
getResult
(
)
;
}

Execute the command remotely and get the results back.

Execute the command remotely and get the results back .


public void endRequest(final OChannelBinaryAsynchClient iNetwork) throws IOException {
    if (iNetwork == null)
      return;

    iNetwork.flush();
    iNetwork.releaseWriteLock();

  }

public void endRequest ( final OChannelBinaryAsynchClient iNetwork ) throws IOException { if ( iNetwork == null ) return ; iNetwork . flush ( ) ; iNetwork . releaseWriteLock ( ) ; }

Ends the request and unlock the write lock


protected String addHost(String host) {
    if (host.startsWith(LOCALHOST))
      host = LOCAL_IP + host.substring("localhost".length());

    if (host.contains("/"))
      host = host.substring(0, host.indexOf("/"));

    // REGISTER THE REMOTE SERVER+PORT
    if (!host.contains(":"))
      host += ":" + (clientConfiguration.getValueAsBoolean(OGlobalConfiguration.CLIENT_USE_SSL) ?
          getDefaultSSLPort() :
          getDefaultPort());
    else if (host.split(":").length < 2 || host.split(":")[1].trim().length() == 0)
      host += (clientConfiguration.getValueAsBoolean(OGlobalConfiguration.CLIENT_USE_SSL) ? getDefaultSSLPort() : getDefaultPort());

    // DISABLED BECAUSE THIS DID NOT ALLOW TO CONNECT TO LOCAL HOST ANYMORE IF THE SERVER IS BOUND TO 127.0.0.1
    // CONVERT 127.0.0.1 TO THE PUBLIC IP IF POSSIBLE
    // if (host.startsWith(LOCAL_IP)) {
    // try {
    // final String publicIP = InetAddress.getLocalHost().getHostAddress();
    // host = publicIP + host.substring(LOCAL_IP.length());
    // } catch (UnknownHostException e) {
    // // IGNORE IT
    // }
    // }

    synchronized (serverURLs) {
      if (!serverURLs.contains(host)) {
        serverURLs.add(host);
        OLogManager.instance().debug(this, "Registered the new available server '%s'", host);
      }
    }

    return host;
  }


public OChannelBinaryAsynchClient beginRequest(final OChannelBinaryAsynchClient network, final byte iCommand,
      OStorageRemoteSession session) throws IOException {
    network.beginRequest(iCommand, session);
    return network;
  }

public OChannelBinaryAsynchClient beginRequest ( final OChannelBinaryAsynchClient network , final byte iCommand , OStorageRemoteSession session ) throws IOException { network . beginRequest ( iCommand , session ) ; return network ; }

Acquire a network channel from the pool. Don't lock the write stream since the connection usage is exclusive.

@param iCommand id. Ids described at {@link OChannelBinaryProtocol}

@return connection to server

Acquire a network channel from the pool . Don t lock the write stream since the connection usage is exclusive .


protected static OObjectDatabaseTx getDatabase() {
    ODatabaseInternal<?> databaseOwner = ODatabaseRecordThreadLocal.instance().get().getDatabaseOwner();
    if (databaseOwner instanceof OObjectDatabaseTx) {
      return (OObjectDatabaseTx) databaseOwner;
    } else if (databaseOwner instanceof ODatabaseDocumentInternal) {
      return new OObjectDatabaseTx((ODatabaseDocumentInternal) databaseOwner);
    }
    throw new IllegalStateException("Current database not of expected type");
  }

protected
static
OObjectDatabaseTx
getDatabase
(
)
{
ODatabaseInternal
<
>
databaseOwner
=
ODatabaseRecordThreadLocal
.
instance
(
)
.
get
(
)
.
getDatabaseOwner
(
)
;
if
(
databaseOwner
instanceof
OObjectDatabaseTx
)
{
return
(
OObjectDatabaseTx
)
databaseOwner
;
}
else
if
(
databaseOwner
instanceof
ODatabaseDocumentInternal
)
{
return
new
OObjectDatabaseTx
(
(
ODatabaseDocumentInternal
)
databaseOwner
)
;
}
throw
new
IllegalStateException
(
"Current database not of expected type"
)
;
}

Gets the current thread database as a ODatabasePojoAbstract, wrapping it where necessary.

Gets the current thread database as a ODatabasePojoAbstract wrapping it where necessary .


public OClientConnection getConnection(final int iChannelId, ONetworkProtocol protocol) {
    // SEARCH THE CONNECTION BY ID
    OClientConnection connection = connections.get(iChannelId);
    if (connection != null)
      connection.setProtocol(protocol);

    return connection;
  }

public
OClientConnection
getConnection
(
final
int
iChannelId
,
ONetworkProtocol
protocol
)
{
// SEARCH THE CONNECTION BY ID
OClientConnection
connection
=
connections
.
get
(
iChannelId
)
;
if
(
connection
!=
)
connection
.
setProtocol
(
protocol
)
;
return
connection
;
}

Retrieves the connection by id.

@param iChannelId id of connection

@return The connection if any, otherwise null


public void kill(final OClientConnection connection) {
    if (connection != null) {
      final ONetworkProtocol protocol = connection.getProtocol();

      try {
        // INTERRUPT THE NEWTORK MANAGER TOO
        protocol.interrupt();
      } catch (Exception e) {
        OLogManager.instance().error(this, "Error during interruption of binary protocol", e);
      }

      disconnect(connection);

      // KILL THE NETWORK MANAGER TOO
      protocol.sendShutdown();
    }
  }

Disconnects and kill the associated network manager.

@param connection connection to kill

Disconnects and kill the associated network manager .


public void interrupt(final int iChannelId) {
    final OClientConnection connection = connections.get(iChannelId);
    if (connection != null) {
      final ONetworkProtocol protocol = connection.getProtocol();
      if (protocol != null)
        // INTERRUPT THE NEWTORK MANAGER
        protocol.softShutdown();
    }
  }

public
void
interrupt
(
final
int
iChannelId
)
{
final
OClientConnection
connection
=
connections
.
get
(
iChannelId
)
;
if
(
connection
!=
)
{
final
ONetworkProtocol
protocol
=
connection
.
getProtocol
(
)
;
if
(
protocol
!=
)
// INTERRUPT THE NEWTORK MANAGER
protocol
.
softShutdown
(
)
;
}
}

Interrupt the associated network manager.

@param iChannelId id of connection

Interrupt the associated network manager .


public boolean disconnect(final int iChannelId) {
    OLogManager.instance().debug(this, "Disconnecting connection with id=%d", iChannelId);

    final OClientConnection connection = connections.remove(iChannelId);

    if (connection != null) {
      OServerPluginHelper.invokeHandlerCallbackOnClientDisconnection(server, connection);
      connection.close();
      removeConnectionFromSession(connection);

      // CHECK IF THERE ARE OTHER CONNECTIONS
      for (Entry<Integer, OClientConnection> entry : connections.entrySet()) {
        if (entry.getValue().getProtocol().equals(connection.getProtocol())) {
          OLogManager.instance()
              .debug(this, "Disconnected connection with id=%d but are present other active channels", iChannelId);
          return false;
        }
      }

      OLogManager.instance().debug(this, "Disconnected connection with id=%d, no other active channels found", iChannelId);
      return true;
    }

    OLogManager.instance().debug(this, "Cannot find connection with id=%d", iChannelId);
    return false;
  }

Disconnects a client connections

@param iChannelId id of connection

@return true if was last one, otherwise false


public void pushDistribCfg2Clients(final ODocument iConfig) {
    if (iConfig == null)
      return;

    final Set<String> pushed = new HashSet<String>();
    for (OClientConnection c : connections.values()) {
      if (!c.getData().supportsLegacyPushMessages)
        continue;

      try {
        final String remoteAddress = c.getRemoteAddress();
        if (pushed.contains(remoteAddress))
          // ALREADY SENT: JUMP IT
          continue;

      } catch (Exception e) {
        // SOCKET EXCEPTION SKIP IT
        continue;
      }

      if (!(c.getProtocol() instanceof ONetworkProtocolBinary) || c.getData().getSerializationImpl() == null)
        // INVOLVE ONLY BINARY PROTOCOLS
        continue;

      final ONetworkProtocolBinary p = (ONetworkProtocolBinary) c.getProtocol();
      final OChannelBinary channel = p.getChannel();
      final ORecordSerializer ser = ORecordSerializerFactory.instance().getFormat(c.getData().getSerializationImpl());
      if (ser == null)
        return;

      final byte[] content = ser.toStream(iConfig, false);

      try {
        // TRY ACQUIRING THE LOCK FOR MAXIMUM 3 SECS TO AVOID TO FREEZE CURRENT THREAD
        if (channel.tryAcquireWriteLock(TIMEOUT_PUSH)) {
          try {
            channel.writeByte(OChannelBinaryProtocol.PUSH_DATA);
            channel.writeInt(Integer.MIN_VALUE);
            channel.writeByte(OChannelBinaryProtocol.REQUEST_PUSH_DISTRIB_CONFIG);
            channel.writeBytes(content);
            channel.flush();

            pushed.add(c.getRemoteAddress());
            OLogManager.instance().debug(this, "Sent updated cluster configuration to the remote client %s", c.getRemoteAddress());

          } finally {
            channel.releaseWriteLock();
          }
        } else {
          OLogManager.instance()
              .info(this, "Timeout on sending updated cluster configuration to the remote client %s", c.getRemoteAddress());
        }
      } catch (Exception e) {
        OLogManager.instance().warn(this, "Cannot push cluster configuration to the client %s", e, c.getRemoteAddress());
      }
    }
  }

Pushes the distributed configuration to all the connected clients.

Pushes the distributed configuration to all the connected clients .


public boolean swap(int index, OIdentifiable newValue) {
    EntriesIterator iter = (EntriesIterator) rawIterator();
    int currIndex = 0;
    while (iter.hasNext()) {
      iter.next();
      if (index == currIndex) {
        iter.swapValueOnCurrent(newValue);
        return true;
      }
      currIndex++;
    }
    return false;
  }

public boolean swap ( int index , OIdentifiable newValue ) { EntriesIterator iter = ( EntriesIterator ) rawIterator ( ) ; int currIndex = 0 ; while ( iter . hasNext ( ) ) { iter . next ( ) ; if ( index == currIndex ) { iter . swapValueOnCurrent ( newValue ) ; return true ; } currIndex ++ ; } return false ; }

for internal use only

@param index
@param newValue

@return


@Override
  public void close() {
    for (Map.Entry<ORID, LockedRecordMetadata> lock : locks.entrySet()) {
      try {
        final LockedRecordMetadata lockedRecordMetadata = lock.getValue();

        if (lockedRecordMetadata.strategy.equals(OStorage.LOCKING_STRATEGY.EXCLUSIVE_LOCK)) {
          ((OAbstractPaginatedStorage) getDatabase().getStorage().getUnderlying()).releaseWriteLock(lock.getKey());
        } else if (lockedRecordMetadata.strategy.equals(OStorage.LOCKING_STRATEGY.SHARED_LOCK)) {
          ((OAbstractPaginatedStorage) getDatabase().getStorage().getUnderlying()).releaseReadLock(lock.getKey());
        }
      } catch (Exception e) {
        OLogManager.instance().debug(this, "Error on releasing lock against record " + lock.getKey(), e);
      }
    }
    locks.clear();
  }

Closes the transaction and releases all the acquired locks.

Closes the transaction and releases all the acquired locks .


public synchronized void synchronizeSchema() {
    OObjectDatabaseTx database = ((OObjectDatabaseTx) ODatabaseRecordThreadLocal.instance().get().getDatabaseOwner());
    Collection<Class<?>> registeredEntities = database.getEntityManager().getRegisteredEntities();
    boolean automaticSchemaGeneration = database.isAutomaticSchemaGeneration();
    boolean reloadSchema = false;
    for (Class<?> iClass : registeredEntities) {
      if (Proxy.class.isAssignableFrom(iClass) || iClass.isEnum() || OReflectionHelper.isJavaType(iClass) || iClass
          .isAnonymousClass())
        return;

      if (!database.getMetadata().getSchema().existsClass(iClass.getSimpleName())) {
        database.getMetadata().getSchema().createClass(iClass.getSimpleName());
        reloadSchema = true;
      }

      for (Class<?> currentClass = iClass; currentClass != Object.class; ) {

        if (automaticSchemaGeneration && !currentClass.equals(Object.class) && !currentClass.equals(ODocument.class)) {
          ((OSchemaProxyObject) database.getMetadata().getSchema()).generateSchema(currentClass, database.getUnderlying());
        }
        String iClassName = currentClass.getSimpleName();
        currentClass = currentClass.getSuperclass();

        if (currentClass == null || currentClass.equals(ODocument.class))
          // POJO EXTENDS ODOCUMENT: SPECIAL CASE: AVOID TO CONSIDER
          // ODOCUMENT FIELDS
          currentClass = Object.class;

        if (database != null && !database.isClosed() && !currentClass.equals(Object.class)) {
          OClass oSuperClass;
          OClass currentOClass = database.getMetadata().getSchema().getClass(iClassName);
          if (!database.getMetadata().getSchema().existsClass(currentClass.getSimpleName())) {
            oSuperClass = database.getMetadata().getSchema().createClass(currentClass.getSimpleName());
            reloadSchema = true;
          } else {
            oSuperClass = database.getMetadata().getSchema().getClass(currentClass.getSimpleName());
            reloadSchema = true;
          }

          if (!currentOClass.getSuperClasses().contains(oSuperClass)) {
            currentOClass.setSuperClasses(Arrays.asList(oSuperClass));
            reloadSchema = true;
          }

        }
      }
    }
    if (database != null && !database.isClosed() && reloadSchema) {
      database.getMetadata().getSchema().reload();
    }
  }

Checks if all registered entities has schema generated, if not it generates it

Checks if all registered entities has schema generated if not it generates it


protected void updateMetadata(final String iName, final String iDescription, final METRIC_TYPE iType) {
    if (iDescription != null && dictionary.putIfAbsent(iName, iDescription) == null)
      types.put(iName, iType);
  }

protected void updateMetadata ( final String iName , final String iDescription , final METRIC_TYPE iType ) { if ( iDescription != null && dictionary . putIfAbsent ( iName , iDescription ) == null ) types . put ( iName , iType ) ; }


@Override
  public ORecordIteratorClusters<REC> last() {
    if (clusterIds.length == 0)
      return this;

    browsedRecords = 0;
    currentClusterIdx = clusterIds.length - 1;

    updateClusterRange();

    current.setClusterId(clusterIds[currentClusterIdx]);

    resetCurrentPosition();
    prevPosition();

    final ORecord record = getRecord();
    currentRecord = readCurrentRecord(record, 0);

    if (currentRecord != null && !include(currentRecord)) {
      currentRecord = null;
      hasPrevious();
    }

    return this;
  }

@ Override public ORecordIteratorClusters < REC > last ( ) { if ( clusterIds . length == 0 ) return this ; browsedRecords = 0 ; currentClusterIdx = clusterIds . length - 1 ; updateClusterRange ( ) ; current . setClusterId ( clusterIds [ currentClusterIdx ] ) ; resetCurrentPosition ( ) ; prevPosition ( ) ; final ORecord record = getRecord ( ) ; currentRecord = readCurrentRecord ( record , 0 ) ; if ( currentRecord != null && ! include ( currentRecord ) ) { currentRecord = null ; hasPrevious ( ) ; } return this ; }

Move the iterator to the end of the range. If no range was specified move to the last record of the cluster.

@return The object itself

Move the iterator to the end of the range . If no range was specified move to the last record of the cluster .


public int nextChar() throws IOException {
    if (missedChar != null) {
      // RETURNS THE PREVIOUS PARSED CHAR
      c = missedChar.charValue();
      missedChar = null;

    } else {
      int read = in.read();
      if (read == -1)
        return -1;

      c = (char) read;

      if (c == '\\') {
        read = in.read();
        if (read == -1)
          return -1;

        char c2 = (char) read;
        if (c2 == 'u') {
          // DECODE UNICODE CHAR
          final StringBuilder buff = new StringBuilder(8);
          for (int i = 0; i < 4; ++i) {
            read = in.read();
            if (read == -1)
              return -1;

            buff.append((char) read);
          }

          cursor += 6;

          return (char) Integer.parseInt(buff.toString(), 16);
        } else {
          // REMEMBER THE CURRENT CHAR TO RETURN NEXT TIME
          missedChar = c2;
        }
      }
    }

    cursor++;

    if (c == NEW_LINE) {
      ++lineNumber;
      columnNumber = 0;
    } else
      ++columnNumber;

    return (char) c;
  }

Returns the next character from the input stream. Handles Unicode decoding.

Returns the next character from the input stream . Handles Unicode decoding .


public Object execute(final Map<Object, Object> iArgs) {
    if (recordIds.isEmpty() && subQuery == null)
      throw new OCommandExecutionException("Cannot execute the command because it has not been parsed yet");

    if (subQuery != null) {
      final List<OIdentifiable> result = new OCommandSQL(subQuery.toString()).execute();
      for (OIdentifiable id : result)
        recordIds.add(id.getIdentity());
    }

    return OFindReferenceHelper.findReferences(recordIds, classList);
  }