diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..fae1a2b
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/.project b/.project
new file mode 100644
index 0000000..295896d
--- /dev/null
+++ b/.project
@@ -0,0 +1,23 @@
+
+
+ orientdb-bug-reports
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..29abf99
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..714351a
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..c7854cb
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,39 @@
+
+ 4.0.0
+ org.gcube.orientdb
+ orientdb-bug-reports
+ 0.0.1-SNAPSHOT
+ OrientDB Bug Reports
+ This project is used to create reproducibility tests for bugs opened to orientdb project
+
+
+
+ 1.8
+ UTF-8
+
+
+
+
+ com.orientechnologies
+ orientdb-graphdb
+ 2.2.18
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${java_version}
+ ${java_version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/gcube/orientdb/ReproduceBug7354.java b/src/main/java/org/gcube/orientdb/ReproduceBug7354.java
new file mode 100644
index 0000000..dc159f2
--- /dev/null
+++ b/src/main/java/org/gcube/orientdb/ReproduceBug7354.java
@@ -0,0 +1,169 @@
+/**
+ *
+ */
+package org.gcube.orientdb;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import com.orientechnologies.orient.client.remote.OServerAdmin;
+import com.orientechnologies.orient.client.remote.OStorageRemote;
+import com.orientechnologies.orient.core.metadata.OMetadata;
+import com.orientechnologies.orient.core.metadata.schema.OClass;
+import com.orientechnologies.orient.core.metadata.schema.OSchema;
+import com.orientechnologies.orient.core.metadata.schema.OType;
+import com.orientechnologies.orient.core.record.impl.ODocument;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.orient.OrientEdgeType;
+import com.tinkerpop.blueprints.impls.orient.OrientGraph;
+import com.tinkerpop.blueprints.impls.orient.OrientGraphFactory;
+import com.tinkerpop.blueprints.impls.orient.OrientGraphNoTx;
+import com.tinkerpop.blueprints.impls.orient.OrientVertex;
+import com.tinkerpop.blueprints.impls.orient.OrientVertexType;
+
+/**
+ * @author Luca Frosini (ISTI - CNR)
+ * This class reproduce orient issue 7354 - https://github.com/orientechnologies/orientdb/issues/7354
+ */
+public class ReproduceBug7354 {
+
+ private static final String HOST = "remote:node01.acme.org;node02.acme.org;node03.acme.org";
+ private static final String ROOT_USERNAME = "root";
+ private static final String ROOT_PASSWORD = "ROOT_PWD";
+
+ private static final String ADMIN_USERNAME = "admin";
+ private static final String ADMIN_PASSWORD = "admin";
+
+ private static final String DB_NAME = "mydb";
+
+ private static final String DATABASE_TYPE = "graph";
+ private static final String STORAGE_MODE = "plocal";
+
+ public static final String MEMORY_FACET = "MemoryFacet";
+
+ public UUID createDBTypesAndContext() throws IOException{
+
+ System.out.println("Going to create DB " + DB_NAME);
+
+ OServerAdmin serverAdmin = new OServerAdmin(HOST)
+ .connect(ROOT_USERNAME,ROOT_PASSWORD);
+
+ serverAdmin.createDatabase(DB_NAME, DATABASE_TYPE,
+ STORAGE_MODE);
+
+ OrientGraphFactory factory = new OrientGraphFactory(HOST + "/" + DB_NAME,
+ ADMIN_USERNAME, ADMIN_PASSWORD).setupPool(1, 10);
+
+ OrientGraphNoTx orientGraphNoTx = factory.getNoTx();
+
+ OMetadata oMetadata = orientGraphNoTx.getRawGraph().getMetadata();
+
+ OSchema oSchema = oMetadata.getSchema();
+ OClass oRestricted = oSchema.getClass("ORestricted");
+
+ OrientVertexType v = orientGraphNoTx.getVertexBaseType();
+ v.addSuperClass(oRestricted);
+
+ OrientEdgeType e = orientGraphNoTx.getEdgeBaseType();
+ e.addSuperClass(oRestricted);
+
+ orientGraphNoTx.createVertexType(MEMORY_FACET);
+
+ orientGraphNoTx.shutdown();
+
+ System.out.println("DB " + DB_NAME + " has been created. Going to create security Context");
+
+ OrientGraph orientGraph = factory.getTx();
+
+ UUID contextUUID = UUID.randomUUID();
+ // Create Reader and Writers Roles and Users for Context identified by provided UUID
+ SecurityContext.createSecurityContext(orientGraph, contextUUID);
+ orientGraph.commit();
+ orientGraph.shutdown();
+
+ return contextUUID;
+ }
+
+ public OrientGraphFactory getFactory(UUID contextUUID){
+
+ String username = SecurityContext.getSecurityRoleOrUserName(
+ SecurityContext.PermissionMode.WRITER,
+ SecurityContext.SecurityType.USER, contextUUID);
+
+ String password = SecurityContext.WRITER_PASSWORD;
+
+ OrientGraphFactory factory = new OrientGraphFactory(HOST + "/" + DB_NAME,
+ username, password).setupPool(1, 10);
+ factory.setConnectionStrategy(OStorageRemote.CONNECTION_STRATEGY
+ .ROUND_ROBIN_CONNECT.toString());
+
+ return factory;
+ }
+
+ public void createVertex(OrientGraphFactory factory, UUID contextUUID){
+
+ System.out.println("Going to create " + MEMORY_FACET + " instance");
+
+ OrientGraph orientGraph = factory.getTx();
+
+ OrientVertex memory = orientGraph.addVertex("class:" + MEMORY_FACET);
+ SecurityContext.addToSecurityContext(orientGraph, memory, contextUUID);
+
+ List list = new ArrayList<>();
+ ODocument oDocument1 = new ODocument();
+ oDocument1 = oDocument1.fromJSON("{\"key1\":\"Value1\"}");
+ list.add(oDocument1);
+
+ ODocument oDocument2 = new ODocument();
+ oDocument2 = oDocument2.fromJSON("{\"key2\":\"Value2\"}");
+ list.add(oDocument2);
+ memory.setProperty("test", list, OType.EMBEDDEDLIST);
+ memory.save();
+
+ orientGraph.commit();
+ orientGraph.shutdown();
+ }
+
+
+ public void updateVertex(OrientGraphFactory factory, UUID contextUUID){
+ System.out.println("Going to update " + MEMORY_FACET + " instance.");
+
+ OrientGraph orientGraph = factory.getTx();
+ Iterable vertexes = orientGraph.getVerticesOfClass(MEMORY_FACET);
+
+ Vertex v = vertexes.iterator().next();
+
+ List list2 = new ArrayList<>();
+ ODocument oDocument3 = new ODocument();
+ oDocument3 = oDocument3.fromJSON("{\"key3\":\"Value3\"}");
+ list2.add(oDocument3);
+
+ ODocument oDocument4 = new ODocument();
+ oDocument4 = oDocument4.fromJSON("{\"key4\":\"Value4\"}");
+ list2.add(oDocument4);
+ ((OrientVertex) v).setProperty("test", list2, OType.EMBEDDEDLIST);
+
+ orientGraph.commit();
+
+ System.out.println("Changes to " + MEMORY_FACET + " committed.");
+
+ orientGraph.shutdown();
+
+ }
+
+ public void execute() throws IOException {
+ UUID contextUUID = createDBTypesAndContext();
+ OrientGraphFactory factory = getFactory(contextUUID);
+ createVertex(factory, contextUUID);
+ updateVertex(factory, contextUUID);
+ System.out.println("DONE");
+ }
+
+ public static void main(String args[]) throws Exception {
+ ReproduceBug7354 reproduceBug7354 = new ReproduceBug7354();
+ reproduceBug7354.execute();
+ }
+
+}
diff --git a/src/main/java/org/gcube/orientdb/SecurityContext.java b/src/main/java/org/gcube/orientdb/SecurityContext.java
new file mode 100644
index 0000000..89f73f9
--- /dev/null
+++ b/src/main/java/org/gcube/orientdb/SecurityContext.java
@@ -0,0 +1,163 @@
+/**
+ *
+ */
+package org.gcube.orientdb;
+
+import java.util.Iterator;
+import java.util.UUID;
+
+import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
+import com.orientechnologies.orient.core.metadata.security.ORestrictedOperation;
+import com.orientechnologies.orient.core.metadata.security.ORole;
+import com.orientechnologies.orient.core.metadata.security.OSecurity;
+import com.orientechnologies.orient.core.metadata.security.OSecurityRole.ALLOW_MODES;
+import com.orientechnologies.orient.core.metadata.security.OUser;
+import com.orientechnologies.orient.core.record.impl.ODocument;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.Edge;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.impls.orient.OrientBaseGraph;
+import com.tinkerpop.blueprints.impls.orient.OrientEdge;
+import com.tinkerpop.blueprints.impls.orient.OrientGraph;
+import com.tinkerpop.blueprints.impls.orient.OrientVertex;
+
+/**
+ * @author Luca Frosini (ISTI - CNR)
+ *
+ */
+public class SecurityContext {
+
+ public static final String DEFAULT_WRITER_ROLE = "writer";
+ public static final String DEFAULT_READER_ROLE = "reader";
+
+ public static final String READER_PASSSWORD = "reader";
+ public static final String WRITER_PASSWORD = "writer";
+
+ public static void addToSecurityContext(OrientGraph orientGraph, Edge edge,
+ UUID context) {
+ OSecurity oSecurity = orientGraph.getRawGraph().getMetadata()
+ .getSecurity();
+ OrientEdge orientEdge = (OrientEdge) edge;
+ SecurityContext.allowSecurityContextRoles(oSecurity,
+ orientEdge.getRecord(), context);
+ }
+
+ public static void addToSecurityContext(OrientGraph orientGraph,
+ Vertex vertex, UUID context) {
+ OSecurity oSecurity = orientGraph.getRawGraph().getMetadata()
+ .getSecurity();
+ OrientVertex orientVertex = (OrientVertex) vertex;
+
+ SecurityContext.allowSecurityContextRoles(oSecurity,
+ orientVertex.getRecord(), context);
+ orientVertex.save();
+
+ Iterable iterable = vertex.getEdges(Direction.BOTH);
+ Iterator iterator = iterable.iterator();
+ while (iterator.hasNext()) {
+ OrientEdge edge = (OrientEdge) iterator.next();
+ SecurityContext.allowSecurityContextRoles(oSecurity,
+ edge.getRecord(), context);
+ edge.save();
+ }
+ }
+
+ private static void allowSecurityContextRoles(OSecurity oSecurity,
+ ODocument oDocument, UUID context) {
+ oSecurity.allowRole(
+ oDocument,
+ ORestrictedOperation.ALLOW_ALL,
+ getSecurityRoleOrUserName(PermissionMode.WRITER,
+ SecurityType.ROLE, context));
+
+ oSecurity.allowRole(
+ oDocument,
+ ORestrictedOperation.ALLOW_READ,
+ getSecurityRoleOrUserName(PermissionMode.READER,
+ SecurityType.ROLE, context));
+
+ oDocument.save();
+ }
+
+
+ public static String getSecurityRoleOrUserName(
+ PermissionMode permissionMode, SecurityType securityType,
+ UUID context) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(permissionMode);
+ stringBuilder.append(securityType);
+ stringBuilder.append("_");
+ stringBuilder.append(context.toString());
+ return stringBuilder.toString();
+ }
+
+ public enum SecurityType {
+ ROLE("Role"), USER("User");
+
+ private final String name;
+
+ private SecurityType(String name) {
+ this.name = name;
+ }
+
+ public String toString() {
+ return name;
+ }
+ }
+
+ public enum PermissionMode {
+ READER("Reader"), WRITER("Writer");
+
+ private final String name;
+
+ private PermissionMode(String name) {
+ this.name = name;
+ }
+
+ public String toString() {
+ return name;
+ }
+ }
+
+
+
+
+
+ public static void createSecurityContext(OrientBaseGraph orientBaseGraph,
+ UUID context) {
+
+ ODatabaseDocumentTx oDatabaseDocumentTx = orientBaseGraph.getRawGraph();
+ OSecurity oSecurity = oDatabaseDocumentTx.getMetadata().getSecurity();
+
+ ORole writer = oSecurity.getRole(DEFAULT_WRITER_ROLE);
+ ORole reader = oSecurity.getRole(DEFAULT_READER_ROLE);
+
+ String writeRoleName = getSecurityRoleOrUserName(PermissionMode.WRITER,
+ SecurityType.ROLE, context);
+ ORole writerRole = oSecurity.createRole(writeRoleName, writer,
+ ALLOW_MODES.DENY_ALL_BUT);
+ writerRole.save();
+
+ String readerRoleName = getSecurityRoleOrUserName(
+ PermissionMode.READER, SecurityType.ROLE, context);
+ ORole readerRole = oSecurity.createRole(readerRoleName, reader,
+ ALLOW_MODES.DENY_ALL_BUT);
+ readerRole.save();
+
+ String writerUserName = getSecurityRoleOrUserName(
+ PermissionMode.WRITER, SecurityType.USER, context);
+ OUser writerUser = oSecurity.createUser(writerUserName,
+ WRITER_PASSWORD, writerRole);
+ writerUser.save();
+
+ String readerUserName = getSecurityRoleOrUserName(
+ PermissionMode.READER, SecurityType.USER, context);
+ OUser readerUser = oSecurity.createUser(readerUserName,
+ READER_PASSSWORD, readerRole);
+ readerUser.save();
+
+ oDatabaseDocumentTx.commit();
+
+ }
+
+}
diff --git a/src/main/resources/Bug7354_StackTrace.txt b/src/main/resources/Bug7354_StackTrace.txt
new file mode 100644
index 0000000..eed1d54
--- /dev/null
+++ b/src/main/resources/Bug7354_StackTrace.txt
@@ -0,0 +1,36 @@
+Going to create DB mydb
+DB mydb has been created. Going to create security Context
+Going to create MemoryFacet instance
+Going to update MemoryFacet instance.
+Exception in thread "main" com.orientechnologies.orient.server.distributed.task.ODistributedOperationException: Quorum 3 not reached for request (id=0.29 task=tx[1]{record_update(#25:0 v.1)} user=#5:4). Elapsed=20ms. Servers in timeout/conflict are:
+ - node03: TX[1]{1}
+Received:
+ - node01: TX[1]{2}
+ - node02: TX[1]{2}
+ - node03: TX[1]{1}
+ DB name="mydb"
+ DB name="mydb"
+ at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
+ at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
+ at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
+ at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
+ at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.throwSerializedException(OChannelBinaryAsynchClient.java:442)
+ at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.handleStatus(OChannelBinaryAsynchClient.java:393)
+ at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.beginResponse(OChannelBinaryAsynchClient.java:275)
+ at com.orientechnologies.orient.client.binary.OChannelBinaryAsynchClient.beginResponse(OChannelBinaryAsynchClient.java:167)
+ at com.orientechnologies.orient.client.remote.OStorageRemote.beginResponse(OStorageRemote.java:2225)
+ at com.orientechnologies.orient.client.remote.OStorageRemote$28.execute(OStorageRemote.java:1396)
+ at com.orientechnologies.orient.client.remote.OStorageRemote$28.execute(OStorageRemote.java:1368)
+ at com.orientechnologies.orient.client.remote.OStorageRemote$2.execute(OStorageRemote.java:198)
+ at com.orientechnologies.orient.client.remote.OStorageRemote.baseNetworkOperation(OStorageRemote.java:243)
+ at com.orientechnologies.orient.client.remote.OStorageRemote.networkOperationRetry(OStorageRemote.java:195)
+ at com.orientechnologies.orient.client.remote.OStorageRemote.networkOperation(OStorageRemote.java:206)
+ at com.orientechnologies.orient.client.remote.OStorageRemote.commit(OStorageRemote.java:1368)
+ at com.orientechnologies.orient.core.tx.OTransactionOptimistic.doCommit(OTransactionOptimistic.java:533)
+ at com.orientechnologies.orient.core.tx.OTransactionOptimistic.commit(OTransactionOptimistic.java:104)
+ at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2840)
+ at com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx.commit(ODatabaseDocumentTx.java:2809)
+ at com.tinkerpop.blueprints.impls.orient.OrientTransactionalGraph.commit(OrientTransactionalGraph.java:182)
+ at org.acme.ReproduceBug7354.updateVertex(ReproduceBug7354.java:148)
+ at org.acme.ReproduceBug7354.execute(ReproduceBug7354.java:160)
+ at org.acme.ReproduceBug7354.main(ReproduceBug7354.java:166)
\ No newline at end of file