/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.editor.model.teneo;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.teneo.hibernate.resource.HibernateResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FlowerTeneoResource extends HibernateResource {
private static final Logger logger = LoggerFactory.getLogger(FlowerTeneoResource.class);
protected FlowerTeneoChangeRecorder changeRecorder;
public FlowerTeneoResource(URI uri) {
super(uri);
}
public FlowerTeneoChangeRecorder getChangeRecorder() {
return changeRecorder;
}
protected void addChangeRecorderIfNeeded(EObject eObject) {
if (changeRecorder == null) {
changeRecorder = new FlowerTeneoChangeRecorder();
changeRecorder.beginRecording(null);
}
if (!eObject.eAdapters().contains(changeRecorder)) {
eObject.eAdapters().add(changeRecorder);
if (logger.isDebugEnabled()) {
logger.debug("Added Change Recorder({} targets) to: {}", changeRecorder.getTargetObjects().size(), eObject);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Added Change Recorder({} targets) NOT NEEDED for {}", changeRecorder.getTargetObjects().size(), eObject);
}
}
}
/**
* {@link #attached(EObject)} calls this method.
*
* <p>
* For a new object tree (not yet persisted in the DB), the mechanism of {@link ResourceImpl} seems to work, therefore this
* method is invoked for every single object in the hierarchy. When loading by ID an object that is not "root", this method
* is called only for the "root" object from the hierarchy.
*
* <p>
* We override this method instead of {@link #attached(EObject)} because {@link #attached(EObject)} gets called twice for the
* one particular case, probably because of a bug. When loading by a ID an object that is not "root", {@link #attached(EObject)}
* is called twice for the root. However this method (invoked from {@link #attached(EObject)}) has an additional check and will only
* be invoked once.
*
* @see #setEResource(InternalEObject, boolean)
*/
@Override
public void addedEObject(EObject eObject) {
super.addedEObject(eObject);
addChangeRecorderIfNeeded(eObject);
}
/**
* This method is invoked when loading an object by ID. When this happens, it's whole hierarchy is retrieved from the DB. So the
* children know their <code>eContainer</code>. However, the opposite is not true. I.e. the parents don't know the children, because
* they sit in a lazy loaded list, which is not loaded.
*
* <p>
* The original logic, invokes {@link #attached(EObject)} for the "root" of this object. However, because of the above, attached won't
* be called for the other objects (e.g. this, this.eContainer(), this.eContainer().eContainer(), etc.). That's why we override this
* method and we climb the hierarchy to add the recorder.
*
* @see #addedEObject(EObject)
*/
@Override
public void setEResource(InternalEObject eobj, boolean force) {
super.setEResource(eobj, force);
while (eobj.eContainer() != null) {
// this loop won't contain the "root", because it will be handled by
// #attached() and #addedEObject()
addChangeRecorderIfNeeded(eobj);
eobj = (InternalEObject) eobj.eContainer();
}
}
@Override
protected void doUnload() {
super.doUnload();
if (changeRecorder != null) {
changeRecorder.dispose();
}
}
@Override
protected EObject getEObjectByID(String id) {
EObject result = super.getEObjectByID(id);
// TODO CS/FP2 oricum aici ar trebui sa lucreze si cu arborescenta
addChangeRecorderIfNeeded(result);
return result;
}
}