package fr.inria.atlanmod.neo4emf.drivers.impl;
/**
* Copyright (c) 2013 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
* Descritpion ! To come
* @author Amine BENELALLAM
* */
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import fr.inria.atlanmod.neo4emf.INeo4emfObject;
import fr.inria.atlanmod.neo4emf.change.impl.Entry;
import fr.inria.atlanmod.neo4emf.drivers.ISerializer;
import fr.inria.atlanmod.neo4emf.impl.Neo4emfObject;
public class Serializer implements ISerializer {
private int maxCount = 50000;
/**
* TODO: Comment this
*/
PersistenceManager manager;
/**
* TODO: Comment this
*/
Map<String, Object> defaultOptions = new HashMap<String, Object>();
private NETransaction currentTx = null;
private int txCount = 0;
// INodeBuilder nodeBuilder;
public Serializer(PersistenceManager manager, int maxTransCount) {
this.manager = manager;
this.maxCount = maxTransCount;
for (int i = 0; i < saveOptions.length; i++)
defaultOptions.put(saveOptions[i], saveDefaultValues[i]);
}
@Override
/**
* @see {@link INeo4emfResource#save()}
*/
public void save(Map<String, Object> options) {
manager.startNewSession();
options = mergeOptions(options);
boolean isTmpSave = (boolean)options.get(TMP_SAVE);
if(!isTmpSave) {
flushTmpSave(options);
System.out.println("flushed");
}
List<Entry> changes = manager.getResource().getChangeLog().changes();
while (!changes.isEmpty()) {
int times = Math.min(maxCount, changes.size());
List<Entry> subset = changes.subList(0, times);
currentTx = manager.createTransaction();
Entry currentEntry = null;
boolean error = false;
try {
for(Entry each : subset) {
currentEntry = each;
each.process(this,isTmpSave);
}
currentTx.success();
subset.clear();
} catch (Exception e) {
System.out.println(currentEntry);
currentTx.abort();
e.printStackTrace();
error = true;
} finally {
currentTx.commit();
txCount = 0;
if(error) return;
}
}
}
// TODO check if it is a good implementation.
// The previous version was to put all the given options in the defaultOptions
// Map. This behavior is not compatible with the TMP_SAVE option, which is one time
// false and one time true, and should be always false by default for convenience (the user
// never call save for a temporary save).
private Map<String,Object> mergeOptions(Map<String,Object> options) {
if(options == null || options.isEmpty()) {
return defaultOptions;
}
Iterator<String> it = defaultOptions.keySet().iterator();
while(it.hasNext()) {
String key = it.next();
if(!options.containsKey(key)) {
options.put(key, defaultOptions.get(key));
}
}
return options;
}
private void flushTmpSave(Map<String,Object> options) {
List<Relationship> rels = manager.getTmpRelationships();
while(!rels.isEmpty()) {
int times = Math.min(maxCount, rels.size());
List<Relationship> subset = rels.subList(0, times);
NETransaction tx = manager.createTransaction();
// TODO give a collection (to handle subset and don't take all the memory by processing the index)
manager.flushTmpRelationships(subset);
subset.clear();
tx.success();
tx.commit();
}
}
public void deleteExistingObject(INeo4emfObject eObject, boolean isTmp) {
if(isTmp) {
this.manager.createDeleteRelationship(eObject);
}
else {
this.manager.deleteNodeFromEObject(eObject);
}
}
private boolean isPrimitive(String str){
if (str.equals("Boolean")
|| str.equals("Integer")
|| str.equals("Short")
|| str.equals("Long")
|| str.equals("Float")
|| str.equals("String")
|| str.equals("Double")
|| str.equals("Byte")
)
return false;
return true;
// TODO debug this instruction
}
@SuppressWarnings("unchecked")
public void setAttributeValue(INeo4emfObject eObject,
EAttribute at, Object newValue, boolean isTmp) {
Node n = manager.getNodeById(eObject);
if(isTmp) {
if(((Neo4emfObject)eObject).getAttributeNodeId() < 0) {
n = manager.createAttributeNodeForEObject(eObject);
txCount += 2;
}
else {
n = manager.getAttributeNodeById(eObject);
}
}
if (newValue!= null && !at.isMany()){
if (at.getEType() instanceof EEnum) {
n.setProperty(at.getName(), newValue.toString());
txCount++;
}
else if (isPrimitive(at.getName())) {
n.setProperty(at.getName(), newValue);
txCount++;
}
else {
n.setProperty(at.getName(), newValue.toString());
txCount++;
}
}
else if (newValue != null && at.isMany()) {
n.setProperty(at.getName(), ((EList<EObject>) newValue).toArray());
txCount++;
}
else if (!at.isMany()) {
if (at.getEType().getName().equals("Boolean")
|| at.getEType().getName().equals("EBoolean"))
n.setProperty(at.getName(), false);
else if (at.getEType().getName().equals("String")
|| at.getEType().getName().equals("EString"))
n.setProperty(at.getName(), "");
else
n.setProperty(at.getName(), 0);
txCount++;
} else {
n.setProperty(at.getName(), new Object[1]);
txCount++;
}
}
public void removeExistingLink(INeo4emfObject eObject, EReference eRef, Object object, boolean isTmp) {
if(isTmp) {
this.manager.createRemoveLinkRelationship(eObject, (INeo4emfObject)object,eRef);
}
else {
this.manager.removeLink(eObject, (INeo4emfObject)object, eRef);
}
}
public void addNewLink(INeo4emfObject eObject, EReference eRef, INeo4emfObject object, boolean isTmp) {
if(isTmp) {
this.manager.createAddLinkRelationship(eObject,object,eRef);
}
else {
this.manager.createLink(eObject, (INeo4emfObject)object, eRef);
}
}
public void createNewObject(INeo4emfObject eObject, boolean isTmp) {
Node n = null;
if (eObject.getNodeId() == -1) {
n = this.manager.createNodefromEObject(eObject,isTmp);
txCount += 2;
} else {
n = this.manager.getNodeById(eObject);
}
{
EList<EAttribute> atrList = eObject.eClass().getEAllAttributes();
Iterator<EAttribute> itAtt = atrList.iterator();
while (itAtt.hasNext()) {
EAttribute at = itAtt.next();
if (eObject.eIsSet(at)) {
setAttributeValue(eObject, at, eObject.eGet(at),false); // false ?
} else {
n.setProperty(at.getName(), "");
txCount++;
}
}
}
{
EList<EReference> refList = eObject.eClass().getEAllReferences();
Iterator<EReference> itRef = refList.iterator();
while (itRef.hasNext()) {
EReference ref = itRef.next();
boolean isSet = false;
try {
isSet = eObject.eIsSet(ref);
} catch (ClassCastException e) {
}
;
if (isSet) {
if (ref.getUpperBound() == -1) {
List<INeo4emfObject> eObjects = (List<INeo4emfObject>) eObject
.eGet(ref);
int idx = 0;
Iterator<INeo4emfObject> it = eObjects.iterator();
while(idx < eObjects.size()) {
// Loop for all the elements contained in the list
while(txCount < maxCount && it.hasNext()) {
INeo4emfObject referencedNeo4emfObject = it.next();
idx++;
if (referencedNeo4emfObject.getNodeId() == -1) {// && referencedNeo4emfObject.eResource() != null) {
Node childNode = this.manager
.createNodefromEObject(referencedNeo4emfObject,isTmp);
txCount+=2;
referencedNeo4emfObject.setNodeId(childNode
.getId());
}
// if(referencedNeo4emfObject.eResource() != null) {
addNewLink(eObject, ref, referencedNeo4emfObject,isTmp);
txCount++;
if(ref.getEOpposite() != null && referencedNeo4emfObject.getSessionId() < eObject.getSessionId()) {
addNewLink(referencedNeo4emfObject, ref.getEOpposite(), eObject, isTmp);
txCount++;
}
// }
}
if(txCount >= maxCount) {
currentTx.success();
currentTx.commit();
currentTx = manager.createTransaction();
txCount = 0;
}
}
} else {
INeo4emfObject referencedNeo4emfObject = (INeo4emfObject) eObject
.eGet(ref);
if (referencedNeo4emfObject.getNodeId() == -1) { // && referencedNeo4emfObject.eResource() != null) {
Node childNode = this.manager
.createNodefromEObject(referencedNeo4emfObject,isTmp);
txCount += 2;
referencedNeo4emfObject
.setNodeId(childNode.getId());
}
// if(referencedNeo4emfObject.eResource() != null) {
addNewLink(eObject, ref, referencedNeo4emfObject,isTmp);
txCount++;
if(ref.getEOpposite() != null && referencedNeo4emfObject.getSessionId() < eObject.getSessionId()) {
addNewLink(referencedNeo4emfObject, ref.getEOpposite(), eObject, isTmp);
txCount++;
}
// }
if(txCount >= maxCount) {
currentTx.success();
currentTx.commit();
currentTx = manager.createTransaction();
txCount = 0;
}
}
}
}
}
}
}