/**
* <copyright>
* </copyright>
*
* $Id: PAnnotatedModelImpl.java,v 1.26 2008/10/13 05:35:43 mtaal Exp $
*/
package org.eclipse.emf.teneo.annotations.pamodel.impl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.ENamedElement;
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.InternalEObject;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEModelElement;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
import org.eclipse.emf.teneo.annotations.pamodel.PamodelPackage;
import org.eclipse.emf.teneo.annotations.pannotation.SequenceGenerator;
import org.eclipse.emf.teneo.annotations.pannotation.SequenceStyleGenerator;
import org.eclipse.emf.teneo.annotations.pannotation.TableGenerator;
/**
* <!-- begin-user-doc --> An implementation of the model object '<em><b>PAnnotated Model</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link org.eclipse.emf.teneo.annotations.pamodel.impl.PAnnotatedModelImpl#getPaEPackages <em>Pa EPackages</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class PAnnotatedModelImpl extends EObjectImpl implements PAnnotatedModel {
private static final Log log = LogFactory.getLog(PAnnotatedModelImpl.class);
@SuppressWarnings("unchecked")
class MapTrackingAdapter extends AdapterImpl {
@Override
public void notifyChanged(Notification msg) {
// TODO handle resolve?
Object msgFeature = msg.getFeature();
if (!msg.isTouch() && msgFeature == PamodelPackage.eINSTANCE.getPAnnotatedEModelElement_ModelElement()) {
switch (msg.getEventType()) {
case Notification.SET:
case Notification.UNSET:
removeMapping((EModelElement) msg.getOldValue());
addMapping((PAnnotatedEModelElement) msg.getNotifier());
break;
}
} else if (msgFeature instanceof EReference && !msg.isTouch()) {
EReference r = (EReference) msgFeature;
if (PamodelPackage.eINSTANCE.getPAnnotatedEModelElement().isSuperTypeOf(r.getEReferenceType()) &&
r.isContainment()) {
switch (msg.getEventType()) {
case Notification.UNSET:
case Notification.SET:
if (msg.getOldValue() != null) {
detach((PAnnotatedEModelElement) msg.getOldValue());
}
if (msg.getNewValue() != null) {
attach((PAnnotatedEModelElement) msg.getNewValue());
}
break;
case Notification.ADD:
if (msg.getNewValue() != null) {
attach((PAnnotatedEModelElement) msg.getNewValue());
}
break;
case Notification.ADD_MANY:
attach((List<? extends Object>) msg.getNewValue());
break;
case Notification.REMOVE:
if (msg.getOldValue() != null) {
detach((PAnnotatedEModelElement) msg.getOldValue());
}
break;
case Notification.REMOVE_MANY:
detach((List<? extends Object>) msg.getNewValue());
break;
}
}
}
super.notifyChanged(msg);
}
};
final MapTrackingAdapter itsMapTrackingAdapter;
/**
* The cached value of the '{@link #getPaEPackages() <em>Pa EPackages</em>}' containment reference list.
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @see #getPaEPackages()
* @generated
* @ordered
*/
protected EList<PAnnotatedEPackage> paEPackages;
/**
* Record the association between the EModelElement and the PAnnotatedEModelElement that are
* contained in this PAnnotatedModel content.
*/
protected final Map<EModelElement, PAnnotatedEModelElement> eElement_to_pElement;
/** Set to true if initialized */
private boolean initialized = false;
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
protected PAnnotatedModelImpl() {
eElement_to_pElement = new HashMap<EModelElement, PAnnotatedEModelElement>();
itsMapTrackingAdapter = new MapTrackingAdapter();
this.eAdapters().add(itsMapTrackingAdapter);
}
/** Return the mapping from epackage elements to annotated package elements */
public Map<EModelElement, PAnnotatedEModelElement> getModelElementMapping() {
return eElement_to_pElement;
}
/** Merge the passed annotated model in this one */
public void merge(PAnnotatedModel pModel) {
eElement_to_pElement.putAll(pModel.getModelElementMapping());
}
/**
* Register the association among a PAnnotatedEModelElement and its annotated EModelElement. If
* another PAnnotatedEModelElement was associatied to the same EModelElement, such association
* will be broken.
*
* <p>
* In order to mantain the consistency of the model, whenever an association among a
* PAnnotatedEModelElement <code>pa</code> and an EModelElement <code>e</code> is broken, the
* annotatedElement feature of <code>pa</code> is unset.
*/
protected void addMapping(PAnnotatedEModelElement target) {
final EModelElement eModelElement = target.getModelElement();
if (eModelElement != null) {
PAnnotatedEModelElement prevAssoc = eElement_to_pElement.get(eModelElement);
if (prevAssoc != null) {
removeMapping(eModelElement);
prevAssoc.setModelElement(null);
}
eElement_to_pElement.put(eModelElement, target);
}
}
/**
* Unregister the association between an <code>EModelElement</code> and the
* <code>PAnnotatedEModelElement</code> that references it via the <code>annotatedElement</code>
* feature.
*/
protected void removeMapping(EModelElement eModelElement) {
final Object prevAssoc = eElement_to_pElement.remove(eModelElement);
assert prevAssoc != null;
}
/**
* Invoked whenever a new PAnnotatedEModelElement is added to the PAnnotatedModel.
*/
protected void attach(PAnnotatedEModelElement aElement) {
aElement.eAdapters().add(0, itsMapTrackingAdapter);
addMapping(aElement);
attach(aElement.eContents());
}
/**
* Invoked whenever a set of new PAnnotatedEModelElement is added to the PAnnotatedModel.
*/
protected void attach(List<? extends Object> aElements) {
for (Object x : aElements) {
if (x instanceof PAnnotatedEModelElement) {
attach((PAnnotatedEModelElement) x);
}
}
}
/**
* Invoked whenever a PAnnotatedEModelElement is removed from the PAnnotatedModel.
*/
protected void detach(PAnnotatedEModelElement aElement) {
aElement.eAdapters().remove(itsMapTrackingAdapter);
ENamedElement annotatedElement = aElement.getModelElement();
if (annotatedElement != null) {
removeMapping(annotatedElement);
}
detach(aElement.eContents());
}
/**
* Invoked whenever a set of PAnnotatedEModelElement is removed from the PAnnotatedModel.
*/
protected void detach(List<? extends Object> aElements) {
for (Object x : aElements) {
if (x instanceof PAnnotatedEModelElement) {
detach((PAnnotatedEModelElement) x);
}
}
}
/**
* Invariant: the eElement_to_pElement map agree with the PAnnotatedModel content.
* <p>
* This method should be used only for debugging. TODO use in validation.
*/
public void invMapIsWellFormed() {
Set<EModelElement> definedUnused = new HashSet<EModelElement>(eElement_to_pElement.keySet());
for (TreeIterator<? extends Object> i = EcoreUtil.getAllContents(eContents()); i.hasNext();) {
Object x = i.next();
if (x instanceof PAnnotatedEModelElement) {
PAnnotatedEModelElement paElement = (PAnnotatedEModelElement) x;
ENamedElement annotatedElement = paElement.getModelElement();
if (annotatedElement != null) {
assert getPAnnotated(annotatedElement) == paElement;
definedUnused.remove(annotatedElement);
}
} else {
i.prune();
}
}
assert definedUnused.isEmpty();
}
/**
* @return Returns the unique <code>PAnnotatedEModelElement</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EModelElement</code>.
*/
public PAnnotatedEModelElement getPAnnotated(EModelElement e) {
checkAnnotatedPresent(e, eElement_to_pElement);
return eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEPackage</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EPackage</code>.
*/
public PAnnotatedEPackage getPAnnotated(EPackage e) {
checkAnnotatedPresent(e, eElement_to_pElement);
return (PAnnotatedEPackage) eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEClass</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EClass</code>.
*/
public PAnnotatedEClass getPAnnotated(EClass e) {
// in this case do not throw an error
if (e.getEPackage() instanceof EcorePackage) {
return (PAnnotatedEClass) eElement_to_pElement.get(e);
}
checkAnnotatedPresent(e, eElement_to_pElement);
return (PAnnotatedEClass) eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEStructuralFeature</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EStructuralFeature</code>.
*/
public PAnnotatedEStructuralFeature getPAnnotated(EStructuralFeature e) {
checkAnnotatedPresent(e, eElement_to_pElement);
return (PAnnotatedEStructuralFeature) eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEDataType</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EDataType</code>.
*/
public PAnnotatedEDataType getPAnnotated(EDataType e) {
// do not check because many datatypes belong to the emf package
return (PAnnotatedEDataType) eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEAttribute</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EAttribute</code>.
*/
public PAnnotatedEAttribute getPAnnotated(EAttribute e) {
checkAnnotatedPresent(e, eElement_to_pElement);
return (PAnnotatedEAttribute) eElement_to_pElement.get(e);
}
/**
* @return Returns the unique <code>PAnnotatedEReference</code> associated (via the
* <code>annotatedElement</code> feature) to the given <code>EReference</code>.
*/
public PAnnotatedEReference getPAnnotated(EReference e) {
checkAnnotatedPresent(e, eElement_to_pElement);
return (PAnnotatedEReference) eElement_to_pElement.get(e);
}
/**
* Checks if there is a annotated model element for the passed emf model element. If not then an
* illegal argument is thrown
*/
private void checkAnnotatedPresent(EModelElement ee, Map<EModelElement, PAnnotatedEModelElement> map) {
if (!isInitialized()) {
return; // at this point the model is not yet fully initialized.
}
if (ee == null) {
throw new IllegalArgumentException(
"Trying to retrieve Annotated Type using null. "
+ "This can occur if not all epackages have been registered with Teneo.\n"
+ "Or this can occur if epackages which refer to eachother are placed in different ecore/xsd files "
+ "and they are not read using one resource set. The reference from one epackage to another must be "
+ "resolvable by EMF.");
}
if (map.get(ee) == null) {
final String name = ee instanceof ENamedElement ? " for: " + ((ENamedElement) ee).getName() : "";
throw new IllegalArgumentException("No annotated model element present " + name + " for type " +
ee.eClass().getName() + " has its epackage been registered with Teneo?");
}
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return PamodelPackage.Literals.PANNOTATED_MODEL;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
public EList<PAnnotatedEPackage> getPaEPackages() {
if (paEPackages == null) {
paEPackages = new EObjectContainmentWithInverseEList<PAnnotatedEPackage>(PAnnotatedEPackage.class, this, PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES, PamodelPackage.PANNOTATED_EPACKAGE__PA_MODEL);
}
return paEPackages;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@SuppressWarnings("unchecked")
@Override
public NotificationChain eInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
return ((InternalEList<InternalEObject>)(InternalEList<?>)getPaEPackages()).basicAdd(otherEnd, msgs);
}
return super.eInverseAdd(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
return ((InternalEList<?>)getPaEPackages()).basicRemove(otherEnd, msgs);
}
return super.eInverseRemove(otherEnd, featureID, msgs);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
return getPaEPackages();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@SuppressWarnings("unchecked")
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
getPaEPackages().clear();
getPaEPackages().addAll((Collection<? extends PAnnotatedEPackage>)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
getPaEPackages().clear();
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case PamodelPackage.PANNOTATED_MODEL__PA_EPACKAGES:
return paEPackages != null && !paEPackages.isEmpty();
}
return super.eIsSet(featureID);
}
/**
* Returns a sequence generator on the basis of its name, if not found then an exception is
* thrown. efeature is passed for debugging purposes.
*/
public SequenceGenerator getSequenceGenerator(EStructuralFeature efeature, String name) {
// TODO: should not only the paepackage of the efeature be checked?
for (PAnnotatedEPackage pae : getPaEPackages()) {
for (SequenceGenerator sg : pae.getSequenceGenerators()) {
if (sg.getName() != null && sg.getName().compareTo(name) == 0) {
return sg;
}
}
}
throw new IllegalStateException("No sequence generator found with the name: " + name + ", name is used in " +
"annotation of element " + efeature.getEContainingClass().getName() + "/" + efeature.getName());
}
public SequenceStyleGenerator getSequenceStyleGenerator(EStructuralFeature efeature, String name) {
// TODO: should not only the paepackage of the efeature be checked?
for (PAnnotatedEPackage pae : getPaEPackages()) {
for (SequenceStyleGenerator sg : pae.getSequenceStyleGenerators()) {
if (sg.getName() != null && sg.getName().compareTo(name) == 0) {
return sg;
}
}
}
throw new IllegalStateException("No sequence generator found with the name: " + name + ", name is used in " +
"annotation of element " + efeature.getEContainingClass().getName() + "/" + efeature.getName());
}
/**
* Returns a table generator on the basis of its name, if not found then an exception is thrown.
* efeature is passed for debugging purposes.
*/
public TableGenerator getTableGenerator(EStructuralFeature efeature, String name) {
// TODO: should not only the paepackage of the efeature be checked?
for (PAnnotatedEPackage pae : getPaEPackages()) {
for (TableGenerator tg : pae.getTableGenerators()) {
if (tg.getName() != null && tg.getName().compareTo(name) == 0) {
return tg;
}
}
for (PAnnotatedEClass pec : pae.getPaEClasses()) {
if (pec.getTableGenerator() != null && pec.getTableGenerator().getName() != null &&
pec.getTableGenerator().getName().compareTo(name) == 0) {
return pec.getTableGenerator();
}
for (PAnnotatedEStructuralFeature pef : pec.getPaEStructuralFeatures()) {
for (TableGenerator tg : pef.getTableGenerators()) {
if (tg.getName() != null && tg.getName().compareTo(name) == 0) {
return tg;
}
}
}
}
}
log.debug("No table generator found with the name: " + name + ", name is used in " + "annotation of element " +
efeature.getEContainingClass().getName() + "/" + efeature.getName());
return null;
}
/**
* @return the initialized
*/
public boolean isInitialized() {
return initialized;
}
/**
* @param initialized
* the initialized to set
*/
public void setInitialized(boolean initialized) {
this.initialized = initialized;
}
private ConcurrentHashMap<String, EClass> entityNameToEClass = new ConcurrentHashMap<String, EClass>();
/** @return the eclass annotated with this entity name. If not found then an exception is thrown */
public EClass getEClass(String entityName) {
EClass eClass;
if ((eClass = entityNameToEClass.get(entityName)) != null) {
return eClass;
}
for (PAnnotatedEPackage aPackage : getPaEPackages()) {
for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
if (aClass.getEntity() != null && aClass.getEntity().getName() != null &&
aClass.getEntity().getName().compareTo(entityName) == 0) {
entityNameToEClass.put(entityName, aClass.getModelEClass());
return aClass.getModelEClass();
}
}
}
throw new IllegalArgumentException("No Annotated EClass for entityName " + entityName);
}
/**
* @return the EClassifier for a certain name. First the eclasses are searched using the name as
* the entityname then the edatatypes are searched.
*/
public EClassifier getEClassifier(String name) {
if (hasEClass(name)) {
return getEClass(name);
}
for (PAnnotatedEPackage aPackage : getPaEPackages()) {
final EClassifier eClassifier = aPackage.getModelEPackage().getEClassifier(name);
if (eClassifier instanceof EDataType) {
return eClassifier;
}
}
throw new IllegalArgumentException("No EClassifier for name " + name);
}
/**
* @return true if there is an EClass with the name as entityname or an EDataType with the name
* passed as a parameter.
*/
public boolean hasEClassifier(String name) {
if (hasEClass(name)) {
return true;
}
for (PAnnotatedEPackage aPackage : getPaEPackages()) {
final EClassifier eClassifier = aPackage.getModelEPackage().getEClassifier(name);
if (eClassifier instanceof EDataType) {
return true;
}
}
return false;
}
/** @return true if there is annotated eclass with the passed entityname */
public boolean hasEClass(String entityName) {
if (entityNameToEClass.get(entityName) != null) {
return true;
}
for (PAnnotatedEPackage aPackage : getPaEPackages()) {
for (PAnnotatedEClass aClass : aPackage.getPaEClasses()) {
if (aClass.getEntity() != null && aClass.getEntity().getName() != null &&
aClass.getEntity().getName().compareTo(entityName) == 0) {
entityNameToEClass.put(entityName, aClass.getModelEClass());
return true;
}
}
}
return false;
}
/** Dump this model to xml */
public String toXML() {
try {
final XMLResourceImpl xmlResource = new XMLResourceImpl();
xmlResource.getContents().add(this);
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final HashMap<String, String> options = new HashMap<String, String>();
options.put(XMLResource.OPTION_PROCESS_DANGLING_HREF, XMLResource.OPTION_PROCESS_DANGLING_HREF_RECORD);
xmlResource.save(bos, options);
final String res = bos.toString();
bos.close();
return res;
} catch (IOException e) {
// todo replace with teneo exception
throw new IllegalStateException("Exception while converting pamodel to a xml string", e);
}
}
} // PAnnotatedModelImpl