@Test
  public void test5CacheUpdatedMultipleDbs() {
    database1 = new ODatabaseDocumentTx(url).open("admin", "admin");
    database2 = new ODatabaseDocumentTx(url).open("admin", "admin");

    // Create docA in db1
    database1.begin(TXTYPE.OPTIMISTIC);
    ODocument vDocA_db1 = database1.newInstance();
    vDocA_db1.field(NAME, "docA");
    database1.save(vDocA_db1);
    database1.commit();

    // Keep the ID.
    ORID vDocA_Rid = vDocA_db1.getIdentity().copy();

    // Update docA in db2
    database2.begin(TXTYPE.OPTIMISTIC);
    ODocument vDocA_db2 = database2.load(vDocA_Rid);
    vDocA_db2.field(NAME, "docA_v2");
    database2.save(vDocA_db2);
    database2.commit();

    // Later... read docA with db1.
    database1.begin(TXTYPE.OPTIMISTIC);
    ODocument vDocA_db1_later = database1.load(vDocA_Rid, null, true);
    Assert.assertEquals(vDocA_db1_later.field(NAME), "docA_v2");
    database1.commit();

    database1.close();
    database2.close();
  }
  @Test
  public void test3RollbackWithCopyCacheStrategy() throws IOException {
    database1 = new ODatabaseDocumentTx(url).open("admin", "admin");
    database2 = new ODatabaseDocumentTx(url).open("admin", "admin");

    database1.getLevel2Cache().setStrategy(STRATEGY.COPY_RECORD);

    // Create docA.
    ODocument vDocA_db1 = database1.newInstance();
    vDocA_db1.field(NAME, "docA");
    database1.save(vDocA_db1);

    // Keep the IDs.
    ORID vDocA_Rid = vDocA_db1.getIdentity().copy();

    database2.begin(TXTYPE.OPTIMISTIC);
    try {
      // Get docA and update in db2 transaction context
      ODocument vDocA_db2 = database2.load(vDocA_Rid);
      vDocA_db2.field(NAME, "docA_v2");
      database2.save(vDocA_db2);

      database1.begin(TXTYPE.OPTIMISTIC);
      try {
        vDocA_db1.field(NAME, "docA_v3");
        database1.save(vDocA_db1);
        database1.commit();
      } catch (OConcurrentModificationException e) {
        Assert.fail("Should not failed here...");
      }
      Assert.assertEquals(vDocA_db1.field(NAME), "docA_v3");

      // Will throw OConcurrentModificationException
      database2.commit();
      Assert.fail("Should throw OConcurrentModificationException");
    } catch (OConcurrentModificationException e) {
      database2.rollback();
    }

    // Force reload all (to be sure it is not a cache problem)
    database1.close();
    database2.close();
    database2 = new ODatabaseDocumentTx(url).open("admin", "admin");

    // docB should be in the last state : "docA_v3"
    ODocument vDocB_db2 = database2.load(vDocA_Rid);
    Assert.assertEquals(vDocB_db2.field(NAME), "docA_v3");

    database1.close();
    database2.close();
  }
  @SuppressWarnings("unchecked")
  @Test
  public void checkVersionsInConnectedDocuments() {
    ODatabaseDocumentTx db = new ODatabaseDocumentTx(url);
    db.open("admin", "admin");

    db.begin();

    ODocument kim = new ODocument("Profile").field("name", "Kim").field("surname", "Bauer");
    ODocument teri = new ODocument("Profile").field("name", "Teri").field("surname", "Bauer");
    ODocument jack = new ODocument("Profile").field("name", "Jack").field("surname", "Bauer");

    ((HashSet<ODocument>) jack.field("following", new HashSet<ODocument>()).field("following"))
        .add(kim);
    ((HashSet<ODocument>) kim.field("following", new HashSet<ODocument>()).field("following"))
        .add(teri);
    ((HashSet<ODocument>) teri.field("following", new HashSet<ODocument>()).field("following"))
        .add(jack);

    jack.save();

    db.commit();

    db.close();
    db.open("admin", "admin");

    ODocument loadedJack = db.load(jack.getIdentity());

    ORecordVersion jackLastVersion = loadedJack.getRecordVersion().copy();
    db.begin();
    loadedJack.field("occupation", "agent");
    loadedJack.save();
    db.commit();
    Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion()));

    loadedJack = db.load(jack.getIdentity());
    Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion()));

    db.close();

    db.open("admin", "admin");
    loadedJack = db.load(jack.getIdentity());
    Assert.assertTrue(!jackLastVersion.equals(loadedJack.getRecordVersion()));
    db.close();
  }
  @SuppressWarnings("unchecked")
  @Test
  public void loadRecordTest() {
    ODatabaseDocumentTx db = new ODatabaseDocumentTx(url);
    db.open("admin", "admin");

    try {
      db.begin();

      ODocument kim = new ODocument("Profile").field("name", "Kim").field("surname", "Bauer");
      ODocument teri = new ODocument("Profile").field("name", "Teri").field("surname", "Bauer");
      ODocument jack = new ODocument("Profile").field("name", "Jack").field("surname", "Bauer");
      ODocument chloe = new ODocument("Profile").field("name", "Chloe").field("surname", "O'Brien");

      ((HashSet<ODocument>) jack.field("following", new HashSet<ODocument>()).field("following"))
          .add(kim);
      ((HashSet<ODocument>) kim.field("following", new HashSet<ODocument>()).field("following"))
          .add(teri);
      ((HashSet<ODocument>) teri.field("following", new HashSet<ODocument>()).field("following"))
          .add(jack);
      ((HashSet<ODocument>) teri.field("following")).add(kim);
      ((HashSet<ODocument>) chloe.field("following", new HashSet<ODocument>()).field("following"))
          .add(jack);
      ((HashSet<ODocument>) chloe.field("following")).add(teri);
      ((HashSet<ODocument>) chloe.field("following")).add(kim);

      int profileClusterId = db.getClusterIdByName("Profile");

      jack.save();
      Assert.assertEquals(jack.getIdentity().getClusterId(), profileClusterId);

      kim.save();
      Assert.assertEquals(kim.getIdentity().getClusterId(), profileClusterId);

      teri.save();
      Assert.assertEquals(teri.getIdentity().getClusterId(), profileClusterId);

      chloe.save();
      Assert.assertEquals(chloe.getIdentity().getClusterId(), profileClusterId);

      db.commit();

      Assert.assertEquals(jack.getIdentity().getClusterId(), profileClusterId);
      Assert.assertEquals(kim.getIdentity().getClusterId(), profileClusterId);
      Assert.assertEquals(teri.getIdentity().getClusterId(), profileClusterId);
      Assert.assertEquals(chloe.getIdentity().getClusterId(), profileClusterId);

      db.close();
      db.open("admin", "admin");

      ODocument loadedChloe = db.load(chloe.getIdentity());
      System.out.println(loadedChloe);
    } finally {
      db.close();
    }
  }
  @Test
  public void test1RollbackOnConcurrentException() throws IOException {
    database1 = new ODatabaseDocumentTx(url).open("admin", "admin");
    database2 = new ODatabaseDocumentTx(url).open("admin", "admin");

    database1.begin(TXTYPE.OPTIMISTIC);

    // Create docA.
    ODocument vDocA_db1 = database1.newInstance();
    vDocA_db1.field(NAME, "docA");
    database1.save(vDocA_db1);

    // Create docB.
    ODocument vDocB_db1 = database1.newInstance();
    vDocB_db1.field(NAME, "docB");
    database1.save(vDocB_db1);

    database1.commit();

    // Keep the IDs.
    ORID vDocA_Rid = vDocA_db1.getIdentity().copy();
    ORID vDocB_Rid = vDocB_db1.getIdentity().copy();

    ORecordVersion vDocA_version = OVersionFactory.instance().createUntrackedVersion();
    ORecordVersion vDocB_version = OVersionFactory.instance().createUntrackedVersion();

    database2.begin(TXTYPE.OPTIMISTIC);
    try {
      // Get docA and update in db2 transaction context
      ODocument vDocA_db2 = database2.load(vDocA_Rid);
      vDocA_db2.field(NAME, "docA_v2");
      database2.save(vDocA_db2);

      // Concurrent update docA via database1 -> will throw OConcurrentModificationException at
      // database2.commit().
      database1.begin(TXTYPE.OPTIMISTIC);
      try {
        vDocA_db1.field(NAME, "docA_v3");
        database1.save(vDocA_db1);
        database1.commit();
      } catch (OConcurrentModificationException e) {
        Assert.fail("Should not failed here...");
      }
      Assert.assertEquals(vDocA_db1.field(NAME), "docA_v3");
      // Keep the last versions.
      // Following updates should failed and reverted.
      vDocA_version = vDocA_db1.getRecordVersion();
      vDocB_version = vDocB_db1.getRecordVersion();

      // Update docB in db2 transaction context -> should be rollbacked.
      ODocument vDocB_db2 = database2.load(vDocB_Rid);
      vDocB_db2.field(NAME, "docB_UpdatedInTranscationThatWillBeRollbacked");
      database2.save(vDocB_db2);

      // Will throw OConcurrentModificationException
      database2.commit();
      Assert.fail("Should throw OConcurrentModificationException");
    } catch (OConcurrentModificationException e) {
      database2.rollback();
    }

    // Force reload all (to be sure it is not a cache problem)
    database1.close();
    database2.getStorage().close();
    database2 = new ODatabaseDocumentTx(url).open("admin", "admin");

    ODocument vDocA_db2 = database2.load(vDocA_Rid);
    Assert.assertEquals(vDocA_db2.field(NAME), "docA_v3");
    Assert.assertEquals(vDocA_db2.getRecordVersion(), vDocA_version);

    // docB should be in the first state : "docB"
    ODocument vDocB_db2 = database2.load(vDocB_Rid);
    Assert.assertEquals(vDocB_db2.field(NAME), "docB");
    Assert.assertEquals(vDocB_db2.getRecordVersion(), vDocB_version);

    database1.close();
    database2.close();
  }
  @Override
  public boolean execute(OHttpRequest iRequest) throws Exception {
    ODatabaseDocumentTx db = getProfiledDatabaseInstance(iRequest);
    String[] urlParts =
        checkSyntax(
            iRequest.url,
            3,
            "Syntax error: fileDownload/<database>/rid/[/<fileName>][/<fileType>].");

    final String fileName = urlParts.length > 3 ? encodeResponseText(urlParts[3]) : "unknown";

    final String fileType =
        urlParts.length > 5
            ? encodeResponseText(urlParts[4]) + '/' + encodeResponseText(urlParts[5])
            : (urlParts.length > 4 ? encodeResponseText(urlParts[4]) : "");

    final String rid = urlParts[2];

    iRequest.data.commandInfo = "Download";
    iRequest.data.commandDetail = rid;

    final ORecordAbstract<?> response;

    try {

      response = db.load(new ORecordId(rid));
      if (response != null) {
        if (response instanceof ORecordBytes) {
          sendORecordBinaryFileContent(
              iRequest,
              OHttpUtils.STATUS_OK_CODE,
              OHttpUtils.STATUS_OK_DESCRIPTION,
              fileType,
              (ORecordBytes) response,
              fileName);
        } else if (response instanceof ORecordSchemaAware) {
          for (OProperty prop : ((ORecordSchemaAware<?>) response).getSchemaClass().properties()) {
            if (prop.getType().equals(OType.BINARY))
              sendBinaryFieldFileContent(
                  iRequest,
                  OHttpUtils.STATUS_OK_CODE,
                  OHttpUtils.STATUS_OK_DESCRIPTION,
                  fileType,
                  (byte[]) ((ORecordSchemaAware<?>) response).field(prop.getName()),
                  fileName);
          }
        } else {
          sendTextContent(
              iRequest,
              OHttpUtils.STATUS_INVALIDMETHOD_CODE,
              "Record requested is not a file nor has a readable schema",
              null,
              OHttpUtils.CONTENT_TEXT_PLAIN,
              "Record requested is not a file nor has a readable schema");
        }
      } else {
        sendTextContent(
            iRequest,
            OHttpUtils.STATUS_INVALIDMETHOD_CODE,
            "Record requested not exists",
            null,
            OHttpUtils.CONTENT_TEXT_PLAIN,
            "Record requestes not exists");
      }
    } catch (Exception e) {
      sendTextContent(
          iRequest,
          OHttpUtils.STATUS_INTERNALERROR_CODE,
          OHttpUtils.STATUS_INTERNALERROR_DESCRIPTION,
          null,
          OHttpUtils.CONTENT_TEXT_PLAIN,
          e.getMessage());
    } finally {
      if (db != null) OSharedDocumentDatabase.release(db);
    }

    return false;
  }