package fr.inria.atlanmod.neo4emf.drivers.impl;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xmi.FeatureNotFoundException;
import org.neo4j.graphdb.Node;
import fr.inria.atlanmod.neo4emf.INeo4emfObject;
import fr.inria.atlanmod.neo4emf.INeoFactory;
import fr.inria.atlanmod.neo4emf.drivers.ILoader;
import fr.inria.atlanmod.neo4emf.impl.Neo4emfObject;
public class Loader implements ILoader {
/**
* the manager and delegator
*/
PersistenceManager manager;
/**
* a Map of Loaded packages
*/
Map<String,EPackage> ePackageMap;
Map<String, Object> defaultOptions;
public Loader (PersistenceManager manager){
this.manager=manager;
ePackageMap = new HashMap<String,EPackage>();
}
/**
* @see ILoader#load(Map)
*/
@Override
public void load(Map<?, ?> options) {
// merge the options
if (options == null)
options = new HashMap<String, Object>();
options= mergeWithDefaultOptions(options);
// Remove the tmp stuff
removeTmpSave();
// TODO introduce the load strategies
if (((String)options.get(LOADING_STRATEGY)).equals(DYNAMIC_LOADING)){
dynamicLoad(options);
} else if (((String)options.get(LOADING_STRATEGY)).equals(FULL_LOADING)) {
fullLoad(options);
} else { staticLoad(options); }
}
private void fullLoad(Map<?, ?> options) {
// TODO Auto-generated method stub
}
private Map<?, ?> mergeWithDefaultOptions(Map<?, ?> options) {
initOptions();
for (int i=0; i< loadOptions.length; i++) {
if (options.containsKey(loadOptions[i])){
defaultOptions.remove(loadOptions[i]);
defaultOptions.put(loadOptions[i], options.get(loadOptions[i])); }
}
return this.defaultOptions;
}
private void initOptions() {
this.defaultOptions = new HashMap<String, Object>();
for (int i=0;i<loadOptions.length; i++ )
defaultOptions.put(loadOptions[i], loadDefaultValues[i]);
}
private void staticLoad(Map<?, ?> options) {
// TODO a meta-partitioning heuristic
}
private void dynamicLoad(Map<?,?> options){
try {
List <Node> nodes= manager.getAllRootNodes();
List <INeo4emfObject> objects = new ArrayList<INeo4emfObject>();
for (Node n : nodes){
INeo4emfObject obj = getObjectsFromNode(n);
// int newId = manager.getNewPartitionID();
// obj.setPartitionId(newId);
objects.add(obj);
// manager.createNewPartitionHistory(newId);
}
manager.addObjectsToContents(objects);
//manager.putAllToProxy(objects);
}catch(Exception e) {
manager.shutdown();
e.printStackTrace();
}
}
/**
* @see ILoader#getAllInstances(EClass, List)
*/
@Override
public EList<INeo4emfObject> getAllInstances(EClass eClass,
List<Node> nodeList) {
// int sizeChange = getChangeLog().size();
EList<INeo4emfObject> eObjectList = new BasicEList<INeo4emfObject>();
//int newId = manager.getNewPartitionID();
//FlatPartition partition = manager.createNewFlatPartition(newId);
for (Node node : nodeList){
String ns_uri = manager.getNodeContainingPackage(node);
Neo4emfObject obj = (Neo4emfObject) getObjectFromNodeIfNotExist(node, eClass); //(INeo4emfObject)loadMetamodelFromURI(ns_uri).getEFactoryInstance().create(eClass);
(obj).eSetDirectResource(manager.getResource());
obj.setNodeId(node.getId());
//obj.setPartitionId(newId);
eObjectList.add(obj);
//partition.put(obj);
}
// manager.createNewPartitionHistory(newId);
// manager.addObjectsToContents(eObjectList);
// manager.putAllToProxy(eObjectList);
// getChangeLog().removeLastChanges(getChangeLog().size()-sizeChange);
return eObjectList;
}
// private IChangeLog<Entry> getChangeLog() {
// return manager.getResource().getChangeLog();
// }
/**
* get an Object from Node
* @param n {@link Node}
* @return {@link INeo4emfObject}
*/
protected INeo4emfObject getObjectsFromNode(Node n) {
String eClassName = manager.getNodeType(n);
Node attributeNode = manager.getAttributeNode(n);
String ns_uri = manager.getNodeContainingPackage(n);
EPackage ePck = loadMetamodelFromURI(ns_uri);
EFactory factory =null;
if (ePck.getEFactoryInstance() == null) {
ePck.setEFactoryInstance(INeoFactory.eINSTANCE);
}
if (ePck.getEFactoryInstance().getClass().getName()
.equals("org.eclipse.emf.ecore.impl.EFactoryImpl")) {
factory = INeoFactory.eINSTANCE;
factory.setEPackage(ePck);
} else {
factory = ePck.getEFactoryInstance();
}
INeo4emfObject obj = (INeo4emfObject) factory.create(getEClassFromNodeName(eClassName, ePck));
obj.setNodeId(n.getId());
if(attributeNode != null) {
obj.setAttributeNodeId(attributeNode.getId());
}
// FIXME the content of this method should be in PersistenceManager (avoid access
// of proxy in other classes)
manager.getProxyManager().putToProxy(obj);
return obj;
}
/**
* Return an {@link EClass} from its class name
* @param eClassName {@link String}
* @param ePck {@link EPackage}
* @return {@link EClass}
*/
protected EClass getEClassFromNodeName(String eClassName, EPackage ePck) {
for (EClassifier eClassifier : ePck.getEClassifiers()) {
if (eClassifier instanceof EClass && eClassifier.getName().equalsIgnoreCase(eClassName))
return (EClass) eClassifier;
}
return null;
}
/**
* Return the EEnum from the eClass if Exist
* @param enumName {@link String}
* @return
*/
protected EEnum getEEnumFromNodeName(String enumName){
for (Map.Entry<String, EPackage> entry : ePackageMap.entrySet()){
for (EClassifier eClassifier : entry.getValue().getEClassifiers() ){
if (eClassifier instanceof EEnum && eClassifier.getName().equals(enumName))
return (EEnum) eClassifier;
}
}
return null;
}
/**
* Load packages from the metamodelUri
* @param metamodelURI {@link String}
* @return {@link EPackage}
*/
protected EPackage loadMetamodelFromURI(String metamodelURI) {
EPackage metamodel = null;
if (ePackageMap.containsKey(metamodelURI)) {
metamodel = ePackageMap.get(metamodelURI);
}else {
if (metamodelURI.equals(EcorePackage.eNS_URI)) {
metamodel = EcorePackage.eINSTANCE;
}
else if(EPackage.Registry.INSTANCE.containsKey(metamodelURI)) {
metamodel = EPackage.Registry.INSTANCE.getEPackage(metamodelURI);
registerSubPackagesIfExists(metamodel);
}
}
return metamodel;
}
private void removeTmpSave() {
// List<Relationship> relationships = manager.getTmpRelationships();
// Iterator<Relationship> itRel = relationships.iterator();
// List<Node> nodes = manager.getTmpNodes();
// Iterator<Node> itNode = nodes.iterator();
// Transaction tx = manager.beginTx();
NETransaction tx = manager.createTransaction();
manager.cleanIndexes();
// while(itRel.hasNext()) {
// itRel.next().delete();
// }
// while(itNode.hasNext()) {
// itNode.next().delete();
// }
tx.success();
// tx.finish();
tx.commit();
}
/**
* register a subPackage if not exists
* @param metamodel
*/
private void registerSubPackagesIfExists(EPackage metamodel) {
ePackageMap.put(metamodel.getNsURI(), metamodel);
for(EObject object : metamodel.eContents()){
if (object instanceof EPackage) registerSubPackagesIfExists((EPackage) object);
}
}
/**
* fetches attributes of an {@link EObject} from the Node
*/
@Override
public void fetchAttributes(EObject obj, Node n, Node attributeNode) {
try{
Object attributeValue = null;
// int size = getChangeLog().size();
for (EAttribute attr : obj.eClass().getEAllAttributes()) {
if(attributeNode != null && attributeNode.hasProperty(attr.getName())) {
attributeValue = attributeNode.getProperty(attr.getName());
}
else if (n.hasProperty(attr.getName())) {
attributeValue = n.getProperty(attr.getName());
}
if(attributeValue != null) {
Class<?> cls = attributeValue.getClass();
if (attributeValue.toString().equals("")) {
if (attr.getEType().getName().equals("Boolean") || attr.getEType().getName().equals("EBoolean")) {
attributeValue = (Boolean) false;
} else if (attr.getEType().getName().equals("String") || attr.getEType().getName().equals("EString")) {
attributeValue = (String) "";
} else {
if (attr.getEType().getName().equals("EByte")) {
attributeValue = new Byte((byte) 0);
} else if (attr.getEType().getName().equals("EBigInteger"))
attributeValue = new BigInteger("0");
else if (attr.getEType().getName().equals("EBigDecimal"))
attributeValue = new BigDecimal("0");
else if (attr.getEType().getName().equals("ELong"))
attributeValue = Long.parseLong("0");
else
attributeValue = (Integer) 0;
}
obj.eSet(attr, attributeValue);
}
else if (attr.getEType() instanceof EEnum) {
EEnum enumCls = getEEnumFromNodeName(attr.getEType().getName());
Object enumObject = enumCls.getEPackage().getEFactoryInstance().createFromString(enumCls, (String) attributeValue);
obj.eSet(attr, enumObject);
} else if (attr.isMany()) {
obj.eSet(attr, Arrays.asList((List<?>) attributeValue));
} else {
obj.eSet(attr, attributeValue);
}
}
// getChangeLog().removeLastChanges(getChangeLog().size() - size);
}
} catch (Exception e) {
manager.shutdown();
e.printStackTrace();
}
}
/**
* Construct the list of links of <b>obj</b> from the node List
*/
@Override
public void getObjectsOnDemand(EObject obj, int featureId, Node node ,List<Node> nodes) throws FeatureNotFoundException {
try {
((INeo4emfObject)obj).setLoadingOnDemand();
// int size = getChangeLog().size();
//
EReference str = Loader.getFeatureFromID(obj, featureId);
if (str == null) {
throw new FeatureNotFoundException("", obj, "", -1, -1);
}
List<INeo4emfObject> objectList = new ArrayList<INeo4emfObject>();
for (Node n : nodes) {
INeo4emfObject object = getObjectsFromNodeIfNotExists(obj, n, featureId);
objectList.add(object);
}
// TODO: Check this code! It causes movements of objects from their
// containers to the root of the resource...
// if (!str.isContainment())
// manager.addObjectsToContents(objectList);
// Set the resource in case it won't be done in eSet
Iterator<INeo4emfObject> it = objectList.iterator();
while(it.hasNext()) {
INeo4emfObject neoObj = it.next();
if(neoObj.eResource() == null) {
((Neo4emfObject)neoObj).eSetDirectResource((Resource.Internal)obj.eResource());
}
}
if (str.isMany()) {
obj.eSet(str, objectList);
} else if (!objectList.isEmpty()) {
obj.eSet(str, objectList.get(0));
}
((INeo4emfObject)obj).unsetLoadingOnDemand();;
// getChangeLog().removeLastChanges(getChangeLog().size() - size);
} catch (FeatureNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
manager.shutdown();
e.printStackTrace();
}
}
//public EObject getContainerOnDemand2 (EObject eObject, int featureId, Node node, Node containerNode) {
//EObject result = null;
// int size = getChangeLog().size();
//result = getObjectsFromNodeIfNotExists(eObject, containerNode, ((INeo4emfObject)eObject).getPartitionId(),true);
//int newId=((INeo4emfObject)eObject).getPartitionId();
//if (!manager.isHead(eObject)){
// newId = manager.createNewPartition(getObjectsFromNode(node),((INeo4emfObject)eObject).getPartitionId());
// manager.createNewPartitionHistory(newId);
// }
//result = getObjectsFromNodeIfNotExists(eObject, containerNode, newId, false, featureId);
//ArrayList<INeo4emfObject> arrayResult =new ArrayList<INeo4emfObject>();
//arrayResult.add((INeo4emfObject)result);
//manager.addObjectsToContents(arrayResult);
//manager.putToProxy((INeo4emfObject)result, Loader.getFeatureFromID(eObject, featureId), newId);
// getChangeLog().removeLastChanges(getChangeLog().size() - size);
//return result;
//}
@Override
public EObject getContainerOnDemand (EObject eObject, int featureId, Node node, Node containerNode) {
EObject result = null;
// int size = getChangeLog().size();
result = getObjectsFromNodeIfNotExists(eObject, containerNode, featureId);
ArrayList<INeo4emfObject> arrayResult =new ArrayList<INeo4emfObject>();
arrayResult.add((INeo4emfObject)result);
manager.addObjectsToContents(arrayResult);
if (manager.getResource().getContents().contains(eObject)) {
manager.getResource().getContents().remove(eObject);
}
//manager.putToProxy((INeo4emfObject)result, Loader.getFeatureFromID(eObject, featureId), newId);
// getChangeLog().removeLastChanges(getChangeLog().size() - size);
return result;
}
/**
* return the <b>Structural Feature from its ID</b>
* @param obj {@link EObject}
* @param featureId {@link Int}
* @return
*/
private static EReference getFeatureFromID(EObject obj,
int featureId) {
EStructuralFeature ref = obj.eClass().getEAllStructuralFeatures().get(featureId);
return (EReference) (ref instanceof EReference ? ref : null);
}
private INeo4emfObject getObjectFromNodeIfNotExist(Node node, EClass eClass) {
INeo4emfObject eObj = manager.getObjectFromProxy(eClass, node);
if (eObj == null ) {
eObj = getObjectsFromNode(node);
}
return eObj;
}
private INeo4emfObject getObjectsFromNodeIfNotExists(EObject obj, Node n, int featureId) {
//EClassifier eClassifier = obj.eClass().getEAllStructuralFeatures().get(featureId).getEType();
/**
* Retrieve the concrete EClass of the associated node. This is
* needed because the cache is filled with concrete EClass and cannot
* retrieve abstract ones.
* @TODO See if it is more interesting than storing only abstract classes
* in the cache.
*/
String eClassName = manager.getNodeType(n);
String ns_uri = manager.getNodeContainingPackage(n);
EPackage ePck = loadMetamodelFromURI(ns_uri);
EFactory factory =null;
if (ePck.getEFactoryInstance() == null) {
ePck.setEFactoryInstance(INeoFactory.eINSTANCE);
}
if (ePck.getEFactoryInstance().getClass().getName()
.equals("org.eclipse.emf.ecore.impl.EFactoryImpl")) {
factory = INeoFactory.eINSTANCE;
factory.setEPackage(ePck);
} else {
factory = ePck.getEFactoryInstance();
}
EClass eClass = getEClassFromNodeName(eClassName, ePck);
return getObjectFromNodeIfNotExist(n, eClass);
}
/**
* Get EMF object from a Neo4j node
* if the node does not exist it creates a new node
* otherwise it returns the given abject after making
* sure that the new partition does not fit more to it
* @param eObject {@link EObject}
* @param node {@link Node}
* @param newID {@link Integer}
* @param forceMove {@link Boolean}
* @param featureId
* @return {@link EObject}
*/
// private INeo4emfObject getObjectsFromNodeIfNotExists(EObject eObject, Node node, int newID, boolean forceMove, int featureId) {
//
// INeo4emfObject eObj = (INeo4emfObject) manager.getObjectFromProxy(node.getId());
// if (eObj == null ) {
// eObj = getObjectsFromNode(node);
// ((INeo4emfObject)eObj).setPartitionId(newID);}
// else {
// int PID = forceMove ? newID :((INeo4emfObject)eObject).getPartitionId();
// ((INeo4emfObject)eObj).setPartitionId(PID);
// if (forceMove){
// manager.moveToPartition(eObj,((INeo4emfObject)eObject).getPartitionId(),PID, featureId);
// manager.setUsageTrace(PID,((INeo4emfObject)eObject).getPartitionId(), featureId, eObject);
// }
// else
// manager.setUsageTrace(((INeo4emfObject)eObject).getPartitionId(),PID, featureId, eObject);
//
// }
//
// return eObj;
// }
public EList<EClass> subClassesOf(EClass eClass) {
EList<EClass> classesList = new BasicEList<EClass>();
EList<EClass> allClasses = getAllClassesInPackages(eClass.getEPackage());
for (EClass cls : allClasses){
if (cls.getEAllSuperTypes().contains(eClass)){
classesList.add(cls);
}
}
classesList.add(eClass);
return classesList;
}
private EList<EClass> getAllClassesInPackages(EPackage ePackage) {
EList<EClass> eClassesList = new BasicEList<EClass>();
for ( EClassifier eClassifier : ePackage.getEClassifiers()){
if (eClassifier instanceof EClass)
eClassesList.add((EClass)eClassifier );
}
return eClassesList;
}
}