Java tutorial
/* * Copyright (c) 2013-2016 Atlanmod INRIA LINA Mines Nantes. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Atlanmod INRIA LINA Mines Nantes - initial API and implementation */ package fr.inria.atlanmod.neoemf.data.blueprints.store; import com.google.common.collect.Iterables; import com.tinkerpop.blueprints.Direction; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Vertex; import fr.inria.atlanmod.neoemf.core.Id; import fr.inria.atlanmod.neoemf.core.PersistentEObject; import fr.inria.atlanmod.neoemf.data.blueprints.BlueprintsPersistenceBackend; import fr.inria.atlanmod.neoemf.data.store.AbstractDirectWriteStore; import fr.inria.atlanmod.neoemf.data.store.PersistentStore; import org.apache.commons.lang3.ArrayUtils; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import java.util.Map; import java.util.Objects; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkElementIndex; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkPositionIndex; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; public class DirectWriteBlueprintsStore extends AbstractDirectWriteStore<BlueprintsPersistenceBackend> { protected static final String SEPARATOR = ":"; protected static final String POSITION = "position"; protected static final String CONTAINER = "eContainer"; protected static final String CONTENTS = "eContents"; protected static final String CONTAINING_FEATURE = "containingFeature"; protected static final String SIZE_LITERAL = "size"; public DirectWriteBlueprintsStore(Resource.Internal resource, BlueprintsPersistenceBackend graph) { super(resource, graph); } @Override protected Object getAttribute(PersistentEObject object, EAttribute eAttribute, int index) { Vertex vertex = persistenceBackend.getVertex(object.id()); String propertyName = eAttribute.getName(); if (eAttribute.isMany()) { checkElementIndex(index, getSize(vertex, eAttribute), "Invalid get index " + index); propertyName += SEPARATOR + index; } return parseProperty(eAttribute, vertex.getProperty(propertyName)); } @Override protected Object getReference(PersistentEObject object, EReference eReference, int index) { Object returnValue = null; Vertex vertex = persistenceBackend.getVertex(object.id()); Vertex referencedVertex; if (!eReference.isMany()) { referencedVertex = Iterables.getOnlyElement(vertex.getVertices(Direction.OUT, eReference.getName()), null); } else { checkElementIndex(index, getSize(vertex, eReference), "Invalid get index " + index); referencedVertex = Iterables.getOnlyElement(vertex.query().labels(eReference.getName()) .direction(Direction.OUT).has(POSITION, index).vertices(), null); } if (nonNull(referencedVertex)) { returnValue = reifyVertex(referencedVertex); } return returnValue; } @Override protected Object setAttribute(PersistentEObject object, EAttribute eAttribute, int index, Object value) { Object returnValue; if (isNull(value)) { returnValue = get(object, eAttribute, index); clear(object, eAttribute); } else { Vertex vertex = persistenceBackend.getOrCreateVertex(object); String propertyName = eAttribute.getName(); if (!eAttribute.isMany()) { Object property = vertex.getProperty(propertyName); returnValue = parseProperty(eAttribute, property); } else { checkElementIndex(index, getSize(vertex, eAttribute)); propertyName += SEPARATOR + index; returnValue = vertex.getProperty(propertyName); } vertex.setProperty(propertyName, serializeToProperty(eAttribute, value)); } return returnValue; } @Override protected Object setReference(PersistentEObject object, EReference eReference, int index, PersistentEObject value) { Object returnValue = null; if (isNull(value)) { returnValue = get(object, eReference, index); clear(object, eReference); } else { Vertex vertex = persistenceBackend.getOrCreateVertex(object); Vertex newReferencedVertex = persistenceBackend.getOrCreateVertex(value); // Update the containment reference if needed if (eReference.isContainment()) { updateContainment(eReference, vertex, newReferencedVertex); } if (!eReference.isMany()) { Edge edge = Iterables.getOnlyElement(vertex.getEdges(Direction.OUT, eReference.getName()), null); if (nonNull(edge)) { Vertex referencedVertex = edge.getVertex(Direction.IN); returnValue = reifyVertex(referencedVertex); edge.remove(); } vertex.addEdge(eReference.getName(), newReferencedVertex); } else { checkElementIndex(index, getSize(vertex, eReference)); Iterable<Edge> edges = vertex.query().labels(eReference.getName()).direction(Direction.OUT) .has(POSITION, index).edges(); for (Edge edge : edges) { Vertex referencedVertex = edge.getVertex(Direction.IN); returnValue = reifyVertex(referencedVertex); edge.remove(); } Edge edge = vertex.addEdge(eReference.getName(), newReferencedVertex); edge.setProperty(POSITION, index); } } return returnValue; } @Override protected boolean isSetAttribute(PersistentEObject object, EAttribute eAttribute) { boolean returnValue = false; Vertex vertex = persistenceBackend.getVertex(object.id()); if (nonNull(vertex)) { String propertyName = eAttribute.getName(); if (eAttribute.isMany()) { propertyName += SEPARATOR + SIZE_LITERAL; } returnValue = nonNull(vertex.getProperty(propertyName)); } return returnValue; } @Override protected boolean isSetReference(PersistentEObject object, EReference eReference) { boolean returnValue = false; Vertex vertex = persistenceBackend.getVertex(object.id()); if (nonNull(vertex)) { returnValue = !Iterables.isEmpty(vertex.getVertices(Direction.OUT, eReference.getName())); } return returnValue; } @Override protected void unsetAttribute(PersistentEObject object, EAttribute eAttribute) { Vertex vertex = persistenceBackend.getVertex(object.id()); String propertyName = eAttribute.getName(); if (eAttribute.isMany()) { propertyName += SEPARATOR + SIZE_LITERAL; Integer size = vertex.getProperty(propertyName); for (int i = 0; i < size; i++) { vertex.removeProperty(eAttribute.getName() + SEPARATOR + i); } } vertex.removeProperty(propertyName); } @Override protected void unsetReference(PersistentEObject object, EReference eReference) { Vertex vertex = persistenceBackend.getVertex(object.id()); if (!eReference.isMany()) { Edge edge = Iterables.getOnlyElement(vertex.getEdges(Direction.OUT, eReference.getName()), null); if (nonNull(edge)) { edge.remove(); } } else { for (Edge edge : vertex.query().labels(eReference.getName()).direction(Direction.OUT).edges()) { edge.remove(); } vertex.removeProperty(eReference.getName() + SEPARATOR + SIZE_LITERAL); } } @Override protected boolean containsAttribute(PersistentEObject object, EAttribute eAttribute, Object value) { return ArrayUtils.contains(toArray(object, eAttribute), value); } @Override protected boolean containsReference(PersistentEObject object, EReference eReference, PersistentEObject value) { Vertex v = persistenceBackend.getOrCreateVertex(object); for (Vertex vOut : v.getVertices(Direction.OUT, eReference.getName())) { if (Objects.equals(vOut.getId(), value.id().toString())) { return true; } } return false; } @Override protected int indexOfAttribute(PersistentEObject object, EAttribute eAttribute, Object value) { return ArrayUtils.indexOf(toArray(object, eAttribute), value); } @Override protected int indexOfReference(PersistentEObject object, EReference eReference, PersistentEObject value) { if (nonNull(value)) { Vertex inVertex = persistenceBackend.getVertex(object.id()); Vertex outVertex = persistenceBackend.getVertex(value.id()); for (Edge e : outVertex.getEdges(Direction.IN, eReference.getName())) { if (Objects.equals(e.getVertex(Direction.OUT), inVertex)) { return e.getProperty(POSITION); } } } return ArrayUtils.INDEX_NOT_FOUND; } @Override protected int lastIndexOfAttribute(PersistentEObject object, EAttribute eAttribute, Object value) { return ArrayUtils.lastIndexOf(toArray(object, eAttribute), value); } @Override protected int lastIndexOfReference(PersistentEObject object, EReference eReference, PersistentEObject value) { int resultValue; if (isNull(value)) { resultValue = ArrayUtils.INDEX_NOT_FOUND; } else { Vertex inVertex = persistenceBackend.getVertex(object.id()); Vertex outVertex = persistenceBackend.getVertex(value.id()); Edge lastPositionEdge = null; for (Edge e : outVertex.getEdges(Direction.IN, eReference.getName())) { if (Objects.equals(e.getVertex(Direction.OUT), inVertex) && (isNull(lastPositionEdge) || (int) e.getProperty(POSITION) > (int) lastPositionEdge.getProperty(POSITION))) { lastPositionEdge = e; } } if (isNull(lastPositionEdge)) { resultValue = ArrayUtils.INDEX_NOT_FOUND; } else { resultValue = lastPositionEdge.getProperty(POSITION); } } return resultValue; } @Override protected void addAttribute(PersistentEObject object, EAttribute eAttribute, int index, Object value) { if (index == PersistentStore.NO_INDEX) { /* * Handle NO_INDEX index, which represent direct-append feature. * The call to size should not cause an overhead because it would have been done in regular * addUnique() otherwise. */ index = size(object, eAttribute); } Vertex vertex = persistenceBackend.getOrCreateVertex(object); Integer size = getSize(vertex, eAttribute); size++; setSize(vertex, eAttribute, size); checkPositionIndex(index, size, "Invalid add index"); for (int i = size - 1; i > index; i--) { Object movingProperty = vertex.getProperty(eAttribute.getName() + SEPARATOR + (i - 1)); vertex.setProperty(eAttribute.getName() + SEPARATOR + i, movingProperty); } vertex.setProperty(eAttribute.getName() + SEPARATOR + index, serializeToProperty(eAttribute, value)); } @Override protected void addReference(PersistentEObject object, EReference eReference, int index, PersistentEObject value) { if (index == PersistentStore.NO_INDEX) { /* * Handle NO_INDEX index, which represent direct-append feature. * The call to size should not cause an overhead because it would have been done in regular * addUnique() otherwise. */ index = size(object, eReference); } Vertex vertex = persistenceBackend.getOrCreateVertex(object); Vertex referencedVertex = persistenceBackend.getOrCreateVertex(value); // Update the containment reference if needed if (eReference.isContainment()) { updateContainment(eReference, vertex, referencedVertex); } Integer size = getSize(vertex, eReference); int newSize = size + 1; checkPositionIndex(index, newSize, "Invalid add index"); if (index != size) { Iterable<Edge> edges = vertex.query().labels(eReference.getName()).direction(Direction.OUT) .interval(POSITION, index, newSize).edges(); // Avoid unnecessary database access for (Edge edge : edges) { int position = edge.getProperty(POSITION); edge.setProperty(POSITION, position + 1); } } Edge edge = vertex.addEdge(eReference.getName(), referencedVertex); edge.setProperty(POSITION, index); setSize(vertex, eReference, newSize); } @Override protected Object removeAttribute(PersistentEObject object, EAttribute eAttribute, int index) { Vertex vertex = persistenceBackend.getVertex(object.id()); Integer size = getSize(vertex, eAttribute); Object returnValue; checkPositionIndex(index, size, "Invalid remove index"); returnValue = parseProperty(eAttribute, vertex.getProperty(eAttribute.getName() + SEPARATOR + index)); int newSize = size - 1; for (int i = newSize; i > index; i--) { Object movingProperty = vertex.getProperty(eAttribute.getName() + SEPARATOR + i); vertex.setProperty(eAttribute.getName() + SEPARATOR + (i - 1), movingProperty); } setSize(vertex, eAttribute, newSize); return returnValue; } @Override protected Object removeReference(PersistentEObject object, EReference eReference, int index) { Vertex vertex = persistenceBackend.getVertex(object.id()); String referenceName = eReference.getName(); Integer size = getSize(vertex, eReference); InternalEObject returnValue = null; checkPositionIndex(index, size, "Invalid remove index"); Iterable<Edge> edges = vertex.query().labels(referenceName).direction(Direction.OUT) .interval(POSITION, index, size).edges(); for (Edge edge : edges) { int position = edge.getProperty(POSITION); if (position == index) { Vertex referencedVertex = edge.getVertex(Direction.IN); returnValue = reifyVertex(referencedVertex); edge.remove(); if (eReference.isContainment()) { for (Edge conEdge : referencedVertex.getEdges(Direction.OUT, CONTAINER)) { conEdge.remove(); } } } else { edge.setProperty(POSITION, position - 1); } } setSize(vertex, eReference, size - 1); // Update size checkNotNull(returnValue); if (eReference.isContainment()) { returnValue.eBasicSetContainer(null, -1, null); ((PersistentEObject) returnValue).resource(null); } return returnValue; } @Override protected void clearAttribute(PersistentEObject object, EAttribute eAttribute) { Vertex vertex = persistenceBackend.getVertex(object.id()); Integer size = getSize(vertex, eAttribute); for (int i = 0; i < size; i++) { vertex.removeProperty(eAttribute.getName() + SEPARATOR + i); } setSize(vertex, eAttribute, 0); } @Override protected void clearReference(PersistentEObject object, EReference eReference) { Vertex vertex = persistenceBackend.getOrCreateVertex(object); for (Edge edge : vertex.query().labels(eReference.getName()).direction(Direction.OUT).edges()) { edge.remove(); } setSize(vertex, eReference, 0); } @Override public int size(InternalEObject object, EStructuralFeature feature) { checkArgument(feature.isMany(), "Cannot compute size of a single-valued feature"); PersistentEObject persistentEObject = PersistentEObject.from(object); Vertex vertex = persistenceBackend.getVertex(persistentEObject.id()); return isNull(vertex) ? 0 : getSize(vertex, feature); } @Override public InternalEObject getContainer(InternalEObject object) { InternalEObject returnValue = null; PersistentEObject persistentEObject = PersistentEObject.from(object); Vertex vertex = persistenceBackend.getVertex(persistentEObject.id()); Vertex containerVertex = Iterables.getOnlyElement(vertex.getVertices(Direction.OUT, CONTAINER), null); if (nonNull(containerVertex)) { returnValue = reifyVertex(containerVertex); } return returnValue; } @Override public EStructuralFeature getContainingFeature(InternalEObject object) { EStructuralFeature resultValue = null; PersistentEObject persistentEObject = PersistentEObject.from(object); Vertex vertex = persistenceBackend.getVertex(persistentEObject.id()); Edge edge = Iterables.getOnlyElement(vertex.getEdges(Direction.OUT, CONTAINER), null); if (nonNull(edge)) { String featureName = edge.getProperty(CONTAINING_FEATURE); Vertex containerVertex = edge.getVertex(Direction.IN); if (nonNull(featureName)) { EObject container = reifyVertex(containerVertex); resultValue = container.eClass().getEStructuralFeature(featureName); } } return resultValue; } protected Integer getSize(Vertex vertex, EStructuralFeature feature) { Integer size = vertex.getProperty(feature.getName() + SEPARATOR + SIZE_LITERAL); return isNull(size) ? 0 : size; } private void setSize(Vertex vertex, EStructuralFeature feature, int size) { vertex.setProperty(feature.getName() + SEPARATOR + SIZE_LITERAL, size); } private void updateContainment(EReference eReference, Vertex parentVertex, Vertex childVertex) { for (Edge edge : childVertex.getEdges(Direction.OUT, CONTAINER)) { edge.remove(); } Edge edge = childVertex.addEdge(CONTAINER, parentVertex); edge.setProperty(CONTAINING_FEATURE, eReference.getName()); } protected InternalEObject reifyVertex(Vertex vertex) { return reifyVertex(vertex, null); } protected InternalEObject reifyVertex(Vertex vertex, EClass eClass) { PersistentEObject internalEObject = persistenceBackend.reifyVertex(vertex, eClass); if (internalEObject.resource() != resource()) { if (Iterables.isEmpty(vertex.getEdges(Direction.OUT, CONTAINER))) { if (!Iterables.isEmpty(vertex.getVertices(Direction.IN, CONTENTS))) { internalEObject.resource(resource()); } // else : not part of the resource } else { internalEObject.resource(resource()); } } return internalEObject; } @Override public EObject eObject(Id uriFragment) { Vertex vertex = persistenceBackend.getVertex(uriFragment); return isNull(vertex) ? null : reifyVertex(vertex); } @Override public EList<EObject> getAllInstances(EClass eClass, boolean strict) { Map<EClass, Iterable<Vertex>> indexHits = persistenceBackend.getAllInstances(eClass, strict); EList<EObject> instances = new BasicEList<>(); for (Map.Entry<EClass, Iterable<Vertex>> entry : indexHits.entrySet()) { for (Vertex instanceVertex : entry.getValue()) { instances.add(reifyVertex(instanceVertex, entry.getKey())); } } return instances; } }