private void populateNodeRelEvent(PrimitiveElement element, TransactionDataImpl result) {
   for (long nodeId : element.nodes.keySet()) {
     CowNodeElement nodeElement = element.nodes.get(nodeId);
     NodeProxy node = nodeManager.newNodeProxyById(nodeId);
     NodeImpl nodeImpl = nodeManager.getNodeForProxy(nodeId, null);
     if (nodeElement.isDeleted()) {
       if (primitiveElement.createdNodes.contains(nodeId)) {
         continue;
       }
       result.deleted(node);
     }
     if (nodeElement.relationshipAddMap != null && !nodeElement.isDeleted()) {
       for (Integer type : nodeElement.relationshipAddMap.keySet()) {
         RelIdArray createdRels = nodeElement.relationshipAddMap.get(type);
         populateNodeRelEvent(element, result, nodeId, createdRels);
       }
     }
     if (nodeElement.relationshipRemoveMap != null) {
       for (Integer type : nodeElement.relationshipRemoveMap.keySet()) {
         Collection<Long> deletedRels = nodeElement.relationshipRemoveMap.get(type);
         for (long relId : deletedRels) {
           if (primitiveElement.createdRelationships.contains(relId)) {
             continue;
           }
           RelationshipProxy rel = nodeManager.newRelationshipProxyById(relId);
           if (rel.getStartNode().getId() == nodeId) {
             result.deleted(nodeManager.newRelationshipProxyById(relId));
           }
         }
       }
     }
     if (nodeElement.propertyAddMap != null && !nodeElement.isDeleted()) {
       for (DefinedProperty data : nodeElement.propertyAddMap.values()) {
         String key = nodeManager.getKeyForProperty(data);
         Object oldValue = nodeImpl.getCommittedPropertyValue(nodeManager, key);
         Object newValue = data.value();
         result.assignedProperty(node, key, newValue, oldValue);
       }
     }
     if (nodeElement.propertyRemoveMap != null) {
       for (DefinedProperty data : nodeElement.propertyRemoveMap.values()) {
         String key = nodeManager.getKeyForProperty(data);
         Object oldValue = data.value();
         if (oldValue == null && !nodeElement.isDeleted()) {
           nodeImpl.getCommittedPropertyValue(nodeManager, key);
         }
         result.removedProperty(node, key, oldValue);
       }
     }
   }
 }
 private void populateNodeRelEvent(
     PrimitiveElement element, TransactionDataImpl result, long nodeId, RelIdArray createdRels) {
   for (RelIdIterator iterator = createdRels.iterator(DirectionWrapper.BOTH);
       iterator.hasNext(); ) {
     long relId = iterator.next();
     CowRelElement relElement = element.relationships.get(relId);
     if (relElement != null && relElement.isDeleted()) {
       continue;
     }
     RelationshipProxy rel = nodeManager.newRelationshipProxyById(relId);
     if (rel.getStartNode().getId() == nodeId) {
       result.created(nodeManager.newRelationshipProxyById(relId));
     }
   }
 }
 private void populateRelationshipPropertyEvents(
     PrimitiveElement element, TransactionDataImpl result) {
   for (long relId : element.relationships.keySet()) {
     CowRelElement relElement = element.relationships.get(relId);
     RelationshipProxy rel = nodeManager.newRelationshipProxyById(relId);
     RelationshipImpl relImpl = nodeManager.getRelationshipForProxy(relId);
     if (relElement.isDeleted()) {
       if (primitiveElement.createdRelationships.contains(relId)) {
         continue;
       }
       // note: this is done in node populate data
       // result.deleted( rel );
     }
     if (relElement.propertyAddMap != null && !relElement.isDeleted()) {
       for (DefinedProperty data : relElement.propertyAddMap.values()) {
         String key = nodeManager.getKeyForProperty(data);
         Object oldValue = relImpl.getCommittedPropertyValue(nodeManager, key);
         Object newValue = data.value();
         result.assignedProperty(rel, key, newValue, oldValue);
       }
     }
     if (relElement.propertyRemoveMap != null) {
       for (DefinedProperty data : relElement.propertyRemoveMap.values()) {
         String key = nodeManager.getKeyForProperty(data);
         Object oldValue = data.value();
         if (oldValue != null && !relElement.isDeleted()) {
           relImpl.getCommittedPropertyValue(nodeManager, key);
         }
         result.removedProperty(rel, key, oldValue);
       }
     }
   }
 }
  @Test
  public void arrayIndexOutOfBoundsInRelTypeArrayWhenCreatingRelationshipsConcurrently()
      throws Exception {
    // GIVEN
    // -- a node manager capable of serving light-weight RelationshipProxy capable of answering
    // getId()
    NodeManager nodeManager = mock(NodeManager.class);
    when(nodeManager.newRelationshipProxyById(anyLong())).thenAnswer(relationshipProxyWithId());

    // -- a node that says it cannot load any more relationships
    NodeImpl node = mock(NodeImpl.class);
    when(node.getMoreRelationships(nodeManager)).thenReturn(LoadStatus.NOTHING);

    // -- a type iterator that at this point contains one relationship (0)
    ControlledRelIdIterator typeIterator = new ControlledRelIdIterator(0L);
    RelationshipIterator iterator =
        new RelationshipIterator(
            new RelIdIterator[] {typeIterator}, node, OUTGOING, nodeManager, false, false);
    // -- go forth one step in the iterator
    iterator.next();

    // WHEN
    // -- one relationship has been returned, and we're in the middle of the next call to next()
    //    typeIterator will get one more relationship in it. To mimic this we control the outcome of
    //    RelIdIterator#hasNext() so that we get to the correct branch in the RelationshipIterator
    // code
    typeIterator.queueHasNextAnswers(false, false, true);
    long otherRelationship = 1, thirdRelationship = 2;
    typeIterator.add(otherRelationship, thirdRelationship);

    // -- go one more step, getting us into the state where the type index in RelationshipIterator
    //    was incremented by mistake. Although this particular call to next() succeeds
    iterator.next();

    // -- call next() again, where the first thing happening is to get the RelIdIterator with the
    //    now invalid type index, causing ArrayIndexOutOfBoundsException
    Relationship returnedThirdRelationship = iterator.next();

    // THEN
    assertEquals(thirdRelationship, returnedThirdRelationship.getId());
  }