package fr.inria.atlanmod.neo4emf.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.lang.ref.ReferenceQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.util.AbstractTreeIterator;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.WrappedException;
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.impl.MinimalEObjectImpl;
import org.eclipse.emf.ecore.resource.Resource.Internal;
import org.eclipse.emf.ecore.util.EContentsEList;
import org.eclipse.osgi.util.NLS;
import org.neo4j.graphdb.Node;
import fr.inria.atlanmod.neo4emf.INeo4emfObject;
import fr.inria.atlanmod.neo4emf.INeo4emfResource;
import fr.inria.atlanmod.neo4emf.change.IChangeLog;
import fr.inria.atlanmod.neo4emf.change.impl.ChangeLogFactory;
import fr.inria.atlanmod.neo4emf.change.impl.Entry;
import fr.inria.atlanmod.neo4emf.change.impl.SetAttribute;
public class Neo4emfObject extends MinimalEObjectImpl implements INeo4emfObject {
protected volatile int loadingOnDemand = 0;
protected volatile int memoryLock = 0;
/**
* eObject ID
*/
private long id = -1;
/**
* Partition ID
*/
private int partition = -1;
/**
* eObject temporary attribute node ID
*/
protected long attributeId = -1;
private int sessionId = -1;
/**
* isProxy flag
*/
protected boolean isProxy = false;
protected ReferenceQueue<Object> garbagedData;
protected NeoObjectData getObjectData() {
return null;
}
/**
* @see INeo4emfObject#getNodeId()
*/
@Override
public long getNodeId() {
return this.id;
}
@Override
public long getAttributeNodeId() {
return this.attributeId;
}
/**
* @see INeo4emfObject#setNodeId()
*/
@Override
public void setNodeId(final long nodeId) {
this.id = nodeId;
}
@Override
public void setAttributeNodeId(final long nodeId) {
this.attributeId = nodeId;
}
@Override
public int getPartitionId() {
return partition;
}
@Override
public void setPartitionId(final int partId) {
this.partition = partId;
}
/**
* Constructor
*/
public Neo4emfObject() {
super();
this.garbagedData = new ReferenceQueue<Object>();
}
public Neo4emfObject(final EClass eClass) {
super();
eSetClass(eClass);
this.garbagedData = new ReferenceQueue<Object>();
}
/**
* Clear the field <b>ID</b>
*/
public void clearId() {
id = -1;
}
/**
* compare two objects of type {@link INeo4emfObject}
*
* @param {@link INeo4emfObject}
* @return {@link int }
*/
@Override
public int compareTo(final INeo4emfObject o) {
return this.equals(o) ? 0 : this.eContainer().eClass().getName()
.compareTo(o.eContainer().eClass().getName());
}
@Override
public boolean eIsProxy() {
// TODO redefine the eIsproxy method
return this.isProxy;
}
@Override
public void setProxy(final boolean isProxy) {
this.isProxy = isProxy;
}
@Override
public void setLoadingOnDemand() {
this.loadingOnDemand++;
}
@Override
public void unsetLoadingOnDemand() {
this.loadingOnDemand--;
}
@Override
public void setMemoryLock() {
this.memoryLock++;
if (memoryLock == 1) {
setDataStrongReferences();
}
}
@Override
public void unsetMemoryLock() {
this.memoryLock--;
if (memoryLock == 0) {
releaseDataStrongReferences();
}
}
@Override
public void setDataStrongReferences() {
// Do nothing, needs to be overridden in subclasses
}
@Override
public void releaseDataStrongReferences() {
// Do nothing, needs to be overridden in subclasses.
}
@Override
public boolean isLoadingOnDemand() {
return this.loadingOnDemand > 0;
}
@Override
public Object eGet(final EStructuralFeature eFeature) {
return eGet(eFeature, true);
}
@Override
public Object eGet(final EStructuralFeature str, boolean resolve) {
return eGet(str, resolve, true);
}
@Override
public Object eGet(final EStructuralFeature eFeature,
final boolean resolve, final boolean coreType) {
try {
setLoadingOnDemand();
int featureID = eDerivedStructuralFeatureID(eFeature);
Assert.isTrue(featureID >= 0,
"Invalid feature : " + eFeature.getName());
return eGet(featureID, resolve, coreType);
} finally {
unsetLoadingOnDemand();
}
}
@Override
public Object eGet(final int featureID, final boolean resolve,
final boolean coreType) {
EStructuralFeature eFeature = eClass().getEStructuralFeature(featureID);
Assert.isNotNull(eFeature, "Invalid feature : " + eFeature);
// agomez - 2013-12-06: Disable notification of GET
// Object result = simpleGet(featureID, resolve, coreType, true);
Object result = simpleGet(featureID, resolve, coreType, false);
if (this.id == -1 || eResource() == null) {
return result;
}
if (!eFeature.isMany()) {
if (result != null) {
return result;
}
} else {
if (!((List<?>) result).isEmpty()) {
return result;
}
}
Assert.isTrue(eResource() != null
&& eResource() instanceof INeo4emfResource,
"The resource is either null or not of type INeo4emfResource");
INeo4emfResource resource = (INeo4emfResource) eResource();
if (eFeature instanceof EAttribute) {
resource.fetchAttributes(this);
} else if (resolve) {
resource.getOnDemand(this, featureID);
}
return simpleGet(featureID, resolve, coreType, false);
}
protected Object eDynamicGet(final int dynamicFeatureID,
final EStructuralFeature eFeature, final boolean resolve,
final boolean coreType) {
Assert.isTrue(dynamicFeatureID >= 0, "invalid Feature with " + eFeature);
Object result = eSettingDelegate(eFeature).dynamicGet(this,
eSettings(), dynamicFeatureID, resolve, coreType);
if (result == null) {
INeo4emfResource resource = (INeo4emfResource) eResource();
if (eFeature instanceof EAttribute) {
resource.fetchAttributes(this);
} else {
resource.getOnDemand(this, dynamicFeatureID
+ eStaticFeatureCount());
}
}
// agomez - 2013-12-06: Disable notification of GET
// return simpleGet(dynamicFeatureID + eStaticFeatureCount(), resolve,
// coreType, true);
return simpleGet(dynamicFeatureID + eStaticFeatureCount(), resolve,
coreType, false);
}
protected Object simpleGet(final int featureID, final boolean resolve,
final boolean coreType, final boolean notificationRequired) {
int dynamicFeatureID = featureID - eStaticFeatureCount();
EStructuralFeature eFeature = eClass().getEStructuralFeature(featureID);
Assert.isTrue(eFeature != null, "Invalid featureID: " + featureID);
Object result = eSettingDelegate(eFeature).dynamicGet(this,
eSettings(), dynamicFeatureID, resolve, coreType);
// TODO check if it can be removed
/*
* if (result != null && notificationRequired) { Notification msg = new
* ENotificationImpl(this, INeo4emfNotification.GET, eFeature, null,
* null); if (getChangeLog() != null) { // TODO Check if it is still
* needed getChangeLog().addNewEntry(msg); } }
*/
return result;
}
private IChangeLog<Entry> getChangeLog() {
return eResource() != null && eResource() instanceof Neo4emfResource ? ((Neo4emfResource) eResource())
.getChangeLog() : null;
}
@Override
protected void eDynamicSet(final int dynamicFeatureID,
final EStructuralFeature eFeature, Object newValue) {
eSettingDelegate(eFeature).dynamicSet(this, eSettings(),
dynamicFeatureID, newValue);
}
@Override
public void eSet(EStructuralFeature eFeature, Object newValue) {
int featureID = eDerivedStructuralFeatureID(eFeature);
Assert.isTrue(featureID >= 0, "Invalid Feature : " + eFeature.getName());
eSet(featureID, newValue);
addChangelogEntry(newValue, eFeature);
}
@Override
public void eSet(int featureID, Object newValue) {
super.eSet(featureID, newValue);
EStructuralFeature eFeature = eClass().getEStructuralFeature(featureID);
int dynamicFeatureID = featureID - eStaticFeatureCount();
Assert.isTrue(eFeature.isChangeable(),
" illegal argument feature Cannot be changed : " + eFeature);
eDynamicSet(dynamicFeatureID, eFeature, newValue);
addChangelogEntry(newValue, eFeature);
}
public void addChangelogEntry(Object newValue, int eStructuralFeatureId) {
addChangelogEntry(newValue,
eClass().getEStructuralFeature(eStructuralFeatureId));
}
public void addChangelogEntry(Object newValue, EStructuralFeature eFeature) {
if (!isLoadingOnDemand() && getChangeLog() != null) {
if (eFeature instanceof EAttribute) {
getChangeLog().add(
new SetAttribute(this, (EAttribute) eFeature, eGet(
eFeature, false), newValue));
} else if (eFeature instanceof EReference) {
EReference ref = (EReference) eFeature;
if(!isLoadingOnDemand() && isLoaded()) {
if (ref.getEOpposite() == null
|| getSessionId() < ((INeo4emfObject)newValue).getSessionId()
|| (getSessionId() == ((INeo4emfObject)newValue).getSessionId()
&& getNodeId() < ((INeo4emfObject)newValue).getNodeId())) {
if (ref.isMany()) {
if (newValue instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<EObject> c = (Collection<EObject>) newValue;
for (EObject elt : c) {
getChangeLog().add(ChangeLogFactory.eINSTANCE.createAddLink(this, (EReference)eFeature, (INeo4emfObject)elt));
}
} else {
getChangeLog().add(ChangeLogFactory.eINSTANCE.createAddLink(this, (EReference)eFeature, (INeo4emfObject)newValue));
}
} else {
getChangeLog().add(ChangeLogFactory.eINSTANCE.createAddLink(this, (EReference)eFeature,(INeo4emfObject)newValue));
}
}
}
} else {
throw new WrappedException(new Exception(NLS.bind(
"Unexpected EStructuralFeature {0}",
eFeature.toString())));
}
}
}
public void addChangelogRemoveEntry(EObject obj, int featureId) {
INeo4emfObject removedObject = (INeo4emfObject)obj;
if (!isLoadingOnDemand() && getChangeLog() != null) {
EReference ref = (EReference)eClass().getEStructuralFeature(featureId);
if(!isLoadingOnDemand() && isLoaded()) {
if (ref.getEOpposite() == null
|| getSessionId() < removedObject.getSessionId()
|| (getSessionId() == removedObject.getSessionId()
&& getNodeId() < removedObject.getNodeId())) {
getChangeLog().add(ChangeLogFactory.eINSTANCE.createRemoveLink(this, ref, removedObject));
}
}
}
}
@Override
protected Object eVirtualValue(int index) {
// handle virtual delegation in the eResource
// Object result = eVirtualValues()[index];
// if (result != null )
// return result;
// else {
//
// }
throw new UnsupportedOperationException();
}
public boolean isLoaded() {
return getNodeId() > -1 & eResource() instanceof INeo4emfResource;
}
public static class NeoObjectData {
}
@Override
public boolean eIsSet(EStructuralFeature eFeature) {
// return simpleGet(eFeature.getFeatureID(),true, true, false) != null;
return eGet(eFeature) != null;
}
public EList<EObject> eResolvedContents() {
return new EContentsEList<EObject>(this) {
@Override
protected boolean resolve() {
return false;
}
};
}
public TreeIterator<EObject> eAllResolvedContents() {
return new AbstractTreeIterator<EObject>(this, false) {
private static final long serialVersionUID = 1L;
@Override
public Iterator<EObject> getChildren(Object object) {
return ((Neo4emfObject) object).eResolvedContents().iterator();
}
};
}
@Override
public void eSetDirectResource(Internal resource) {
super.eSetDirectResource(resource);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null) {
return false;
} else if (obj.getClass() != this.getClass()) {
return false;
} else if (((Neo4emfObject) obj).getNodeId() == -1) {
return false;
} else if (this.getNodeId() == -1) {
return false;
} else {
return ((Neo4emfObject) obj).getNodeId() == this.getNodeId();
}
}
@Override
public void saveAllAttributesTo(Node n) {
throw new UnsupportedOperationException("Unsupported Method.");
}
@Override
public void loadAllAttributesFrom(Node n) {
throw new UnsupportedOperationException("Unsupported Method.");
}
@Override
public void saveAllReferencesTo(Node n) {
throw new UnsupportedOperationException("Unsupported Method.");
}
@Override
public void loadAllReferencesFrom(Node n) {
throw new UnsupportedOperationException("Unsupported Method.");
}
/**
* TODO is it still needed ?
*/
@Override
public int hashCode() {
if (id == -1) {
return super.hashCode();
}
int prime = 17;
int result = 1;
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
@Override
public int getSessionId() {
return sessionId;
}
@Override
public void setSessionId(int sessionId) {
this.sessionId = sessionId;
}
}