/*
* Copyright (c) 2004- michael lawley and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation
* which accompanies this distribution, and is available by writing to
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contributors:
* michael lawley
*
*
*
*/
package tefkat.engine.runtime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EObjectImpl;
/**
* @author lawley
*
*/
final public class DynamicObject extends EObjectImpl {
static int counter = 0;
private EObject staticObj = null;
public DynamicObject() {
this(EcorePackage.eINSTANCE.getEObject());
}
public DynamicObject(EClass eClass) {
incrementCounter();
eSetClass(eClass);
}
private static void incrementCounter() {
counter++;
}
public boolean hasStaticInstance() {
return null != staticObj;
}
public EObject getStaticInstance() {
if (null == staticObj) {
EClass eClass = eClass();
if (eClass.isAbstract()) {
throw new IllegalArgumentException("Cannot create an instance of the abstract type: " + eClass.getName());
}
staticObj = eClass.getEPackage().getEFactoryInstance().create(eClass);
// System.out.println("New static instance: " + staticObj.hashCode() + " of type " + eClass.getName());
// Copy over all property values
EPropertiesHolder props = eProperties();
if (props.getEClass() != null && props.hasSettings()) {
List features = eClass.getEAllStructuralFeatures();
for (Iterator itr = features.iterator(); itr.hasNext();) {
EStructuralFeature feature = (EStructuralFeature) itr.next();
staticObj.eSet(feature, eGet(feature));
// System.out.println(" F: " + feature.getName());
}
}
// Update all external references
for (Iterator itr = actions.iterator(); itr.hasNext();) {
Action action = (Action) itr.next();
action.doIt(staticObj);
}
// Update containing resource
// List contents = eResource().getContents();
// contents.remove(this);
// contents.add(staticObj);
}
return staticObj;
}
/**
* Converts this Object to a dynamic object with a new type that is a subtype of the current type, preserving any existing property values.
*
* @param newEClass the new type for this Object
* @throws IllegalArgumentException if newEClass is not a subtype of this Object's current type
* @see org.eclipse.emf.ecore.InternalEObject#eSetClass(org.eclipse.emf.ecore.EClass)
*/
public void narrow(EClass newEClass) throws IllegalArgumentException {
if (!eClass().equals(EcorePackage.eINSTANCE.getEObject()) && !eClass().isSuperTypeOf(newEClass)) {
throw new IllegalArgumentException(
"The class "
+ newEClass.getName()
+ " is not a subtype of the Object's current type "
+ eClass().getName());
}
EPropertiesHolder props = eProperties();
if (props.getEClass() != null && props.hasSettings()) {
int staticSize = eStaticFeatureCount();
int oldSize =
eClass().getEAllStructuralFeatures().size() - staticSize;
if (oldSize > 0) {
int newSize =
newEClass.getEAllStructuralFeatures().size() - staticSize;
if (newSize > oldSize) {
List oldValues = new ArrayList(oldSize);
for (int i = 0; i < oldSize; i++) {
oldValues.add(props.dynamicGet(i));
}
props.allocateSettings(newSize);
for (int i = 0; i < oldSize; i++) {
props.dynamicSet(i, oldValues.get(i));
}
}
}
}
eSetClass(newEClass);
}
List actions = new ArrayList();
public void addReferenceFrom(final EObject instance, final EStructuralFeature feature) {
actions.add(new AddSingleValuedReferenceAction(instance, feature));
}
public void addMultiReferenceFrom(final EObject instance, final EStructuralFeature feature) {
actions.add(new AddMultiValuedReferenceAction(feature, this, instance));
}
public String toString() {
return "_" + hashCode() + ":" + eClass().getName();
}
static interface Action {
public void doIt(EObject obj);
}
private static final class AddMultiValuedReferenceAction implements Action {
private final EStructuralFeature feature;
private final DynamicObject dynObj;
private final EObject instance;
AddMultiValuedReferenceAction(EStructuralFeature feature, DynamicObject dynObj, EObject instance) {
super();
this.feature = feature;
this.dynObj = dynObj;
this.instance = instance;
}
public void doIt(EObject obj) {
EObject referringInstance =
(instance instanceof DynamicObject && ((DynamicObject) instance).hasStaticInstance())
? ((DynamicObject) instance).getStaticInstance()
: instance;
List featureValues = (List) referringInstance.eGet(feature);
int index = featureValues.indexOf(dynObj);
featureValues.set(index, obj);
// System.out.println(" M: " + feature.getName());
}
}
private static final class AddSingleValuedReferenceAction implements Action {
private final EObject instance;
private final EStructuralFeature feature;
AddSingleValuedReferenceAction(EObject instance, EStructuralFeature feature) {
super();
this.instance = instance;
this.feature = feature;
}
public void doIt(EObject obj) {
EObject referringInstance =
(instance instanceof DynamicObject && ((DynamicObject) instance).hasStaticInstance())
? ((DynamicObject) instance).getStaticInstance()
: instance;
referringInstance.eSet(feature, obj);
// System.out.println(" R: " + feature.getName());
}
}
}