com.dooapp.gaedo.blueprints.operations.Updater Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gaedo-blueprints Show documentation
Show all versions of gaedo-blueprints Show documentation
Implementation of gaedo mechanisms backed by blueprints graph layer
package com.dooapp.gaedo.blueprints.operations;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.CascadeType;
import com.dooapp.gaedo.blueprints.AbstractBluePrintsBackedFinderService;
import com.dooapp.gaedo.blueprints.CantCreateAVertexForALiteralException;
import com.dooapp.gaedo.blueprints.GraphDatabaseDriver;
import com.dooapp.gaedo.blueprints.GraphUtils;
import com.dooapp.gaedo.blueprints.ObjectCache;
import com.dooapp.gaedo.blueprints.Properties;
import com.dooapp.gaedo.blueprints.transformers.LiteralHelper;
import com.dooapp.gaedo.blueprints.transformers.Literals;
import com.dooapp.gaedo.properties.AbstractPropertyAdapter;
import com.dooapp.gaedo.properties.Property;
import com.dooapp.gaedo.utils.CollectionUtils;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.Vertex;
public class Updater {
public class UpdateProperties extends AbstractCardinalityDistinguishingOperation {
private final GraphDatabaseDriver driver;
private final Graph database;
private final AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service;
private final ObjectCache objectsBeingAccessed;
private final Object toUpdate;
private final Vertex objectVertex;
private UpdateProperties(GraphDatabaseDriver driver, Graph database, AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service,
ObjectCache objectsBeingAccessed, Object toUpdate, Vertex objectVertex) {
this.driver = driver;
this.database = database;
this.service = service;
this.objectsBeingAccessed = objectsBeingAccessed;
this.toUpdate = toUpdate;
this.objectVertex = objectVertex;
}
@Override
protected void operateOnSingle(Property p, CascadeType cascade) {
updateSingle(service, driver, database, p, toUpdate, objectVertex, cascade, objectsBeingAccessed);
}
@Override
protected void operateOnMap(Property p, CascadeType cascade) {
updateMap(service, driver, database, p, toUpdate, objectVertex, cascade, objectsBeingAccessed);
}
@Override
protected void operateOnCollection(Property p, CascadeType cascade) {
updateCollection(service, driver, database, p, toUpdate, objectVertex, cascade, objectsBeingAccessed);
}
}
public static final Boolean ELEMENT_IN_COLLECTION_MARKER = Boolean.TRUE;
public static final String ELEMENT_IN_COLLECTION_MARKER_GRAPH_VALUE = Literals.get(ELEMENT_IN_COLLECTION_MARKER.getClass()).toString(ELEMENT_IN_COLLECTION_MARKER);
private static final Logger logger = Logger.getLogger(Updater.class.getName());
/**
* Create or update given object
*
* @param service
* source of modification
* @param driver
* TODO
* @param objectVertexId
* object expected vertex id
* @param objectVertex
* vertex corresponding to object to update
* @param valueClass
* class of the value to be updated here
* @param containedProperties
* list of contained properties
* @param toUpdate
* object to update
* @param cascade
* kind of cascade used for dependent properties
* @param objectsBeingUpdated
* map containing subgraph of obejcts currently being updated,
* this is used to avoid loops, and NOT as a cache
* @return updated object
*/
public Object performUpdate(AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service, GraphDatabaseDriver driver,
String objectVertexId, Vertex objectVertex, Class> valueClass, Map> containedProperties,
Object toUpdate, CascadeType cascade, ObjectCache objectsBeingUpdated) {
Graph database = service.getDatabase();
// it's in fact an object creation
if (objectVertex == null) {
if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "object " + objectVertexId.toString() + " has never before been seen in graph, so create central node for it");
}
objectVertex = driver.createEmptyVertex(valueClass, objectVertexId, toUpdate);
// Create a value for that node (useful for RDF export)
driver.setValue(objectVertex, objectVertexId);
}
// Here come the caching !
DataType updated = (DataType) objectsBeingUpdated.get(objectVertexId);
if (updated == null) {
try {
objectsBeingUpdated.put(objectVertexId, toUpdate);
updateProperties(service, driver, database, toUpdate, objectVertex, containedProperties, cascade, objectsBeingUpdated);
return toUpdate;
} finally {
objectsBeingUpdated.remove(objectVertexId);
}
} else {
return updated;
}
}
/**
* Update all properties of given object
*
* @param driver
* TODO
* @param toUpdate
* object to update
* @param objectVertex
* object root vertex
* @param containedProperties
* map linking each object property to the cascade types
* associated to it (allows us to easily see if there is any
* cascade to perform on object)
* @param cascade
* cascade type used to perform this operation, depend if this
* method is called from a {@link #create(Object)} or an
* {@link #update(Object)}
* @param objectsBeingAccessed
* cache of objects being accessed during that write
*/
private void updateProperties(
final AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service,
final GraphDatabaseDriver driver,
final Graph database,
final Object toUpdate,
final Vertex objectVertex,
Map> containedProperties,
CascadeType cascade,
final ObjectCache objectsBeingAccessed) {
new OperateOnProperties().execute(containedProperties, cascade, new UpdateProperties(driver, database, service, objectsBeingAccessed, toUpdate, objectVertex));
// Migrator property has been added to object if needed
// it's also the case of classes list
}
/**
* Persisting a map consist into considering each map entry as an object of
* the map entries collection, then associating each entry object to its
* contained key and value. To make this association as easy (and readable
* as posisble) map entries keys are their keys objects ids (if managed) or
* values) elsewhere, and values are their values ids (if managed) or values
* (elsewhere). Notice a link is always made between a map entry and both
* its key and value.
*
* @param driver
* TODO
* @param p
* property containing that map
* @param toUpdate
* map to update
* @param rootVertex
* object root vertex
* @param cascade
* used cascade type, can be either {@link CascadeType#PERSIST}
* or {@link CascadeType#MERGE}
*/
private void updateMap(AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service, GraphDatabaseDriver driver, Graph database,
Property p, Object toUpdate, Vertex rootVertex, CascadeType cascade, ObjectCache objectsBeingAccessed) {
// Cast should work like a charm
Map, ?> value = (Map, ?>) p.get(toUpdate);
// As a convention, null values are never stored
if (value != null /*
* && value.size()>0 that case precisely created
* https://github.com/Riduidel/gaedo/issues/13
*/) {
// Get previously existing vertices
Iterable existingIterator = service.getStrategy().getOutEdgesFor(rootVertex, p);
// Do not change previously existing vertices if they correspond to
// new ones
// Which is done in that call : as vertex is always looked up before
// creation, there is little duplication risk
// or at last that risk should be covered by selected Blueprints
// implementation
Collection newVertices = createMapVerticesFor(service, value, cascade, objectsBeingAccessed);
Map oldVertices = new HashMap();
for (Edge e : existingIterator) {
Vertex inVertex = e.getVertex(Direction.IN);
if (newVertices.contains(inVertex)) {
newVertices.remove(inVertex);
} else {
oldVertices.put(inVertex, e);
}
}
// Now the have been collected, remove all old vertices
for (Map.Entry entry : oldVertices.entrySet()) {
GraphUtils.removeSafely(database, entry.getValue());
// TODO also remove map entry vertex associated edges
}
// And finally add new vertices
for (Vertex newVertex : newVertices) {
driver.createEdgeFor(rootVertex, newVertex, p);
}
}
}
/**
* Update given collection by creating a set of edges/vertices for each
* element
*
* @param driver
* TODO
* @param p
* properties to update associated vertices for
* @param toUpdate
* source object to update
* @param rootVertex
* vertex associated to toUpdate
* @param cascade
* used cascade type, can be either {@link CascadeType#PERSIST}
* or {@link CascadeType#MERGE}
*
* @category update
*/
private void updateCollection(AbstractBluePrintsBackedFinderService extends Graph, DataType, ?> service, GraphDatabaseDriver driver,
Graph database, Property p, Object toUpdate, Vertex rootVertex, CascadeType cascade, ObjectCache objectsBeingAccessed) {
// Cast should work like a charm
Collection> value = (Collection>) p.get(toUpdate);
// As a convention, null values are never stored
if (value != null /*
* && value.size()>0 that case precisely created
* https://github.com/Riduidel/gaedo/issues/13
*/) {
// Get previously existing vertices
Iterable previousEdges = service.getStrategy().getOutEdgesFor(rootVertex, p);
// Get the new, updated Collection of vertices (which is already
// sorted).
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy