Home » Modeling » EMF "Technology" (Ecore Tools, EMFatic, etc) » EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed
|
Re: EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed [message #1031034 is a reply to message #1030950] |
Mon, 01 April 2013 04:41 |
Ed Merks Messages: 33142 Registered: July 2009 |
Senior Member |
|
|
David,
Comments below.
On 01/04/2013 3:45 AM, David Rees wrote:
> When EPackageImpl.getEClassifiers().remove(EClassifier) is called, the
> underlying EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap
> does not have its corresponding entry deleted.
It's not updated when you rename something either, nor are things like
org.eclipse.emf.ecore.impl.EPackageImpl.eNameToEClassifierMap
>
> So when I later try to load a model using the modified EPackage I get
> a BasicIndexOutOfBoundsException in
> BasicExtendedMetaData$EPackageExtendedMetaDataImpl.getType(String)
> line: 2173. In particular the problem is the following lines which
> assume the nameToClassifierMap's size is less than or equal to the
> eClassifier's size. Unfortunately because the entries were not deleted
> the nameToClassifierMap is actually larger than the eClassifiers.
>
> if (nameToClassifierMap.size() != size)
> {
> for (int i = 0; i < originalMapSize; ++i)
> {
> EClassifier eClassifier = eClassifiers.get(i);
>
> Am I using things somehow incorrectly?
Perhaps. These types of things aren't expected to be used on a model
that mutates and a model that's been used to create instances isn't
expected to mutate once it's used in that way.
> I know we can't change a metamodel once it's model is loaded, but I
> had assumed that we should be able to modify a loaded metamodel before
> we load the model.
Before it's used to create instances (with loading just being one of those).
>
> If we are using it correctly then it I guess the
> EPackageExtendedMetaDataImpl should be updated to register for
> notifications on eClassifiers so it can delete entries when needed.
What are you using extended meta data for? How are you using it in
combination with deleting classifiers from a package (or renaming them,
or deleting/renaming features in a class, all of which will have similar
issues). The list of all the things that are cached and affected by
arbitrary changes you make to the model is very long...
If you use this constructor you can flush the map (or create a new
instances) whenever you make these types of changes.
org.eclipse.emf.ecore.util.BasicExtendedMetaData.BasicExtendedMetaData(String,
Registry, Map<EModelElement, EAnnotation>)
>
> Thanks,
> dave
>
> Eclipse Modeling Framework Runtime and Tools
> Version: 2.9.0.v20130204-1146
> Build id: S201302041146
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed [message #1031364 is a reply to message #1031034] |
Mon, 01 April 2013 16:19 |
David Rees Messages: 47 Registered: September 2012 |
Member |
|
|
Ed Merks wrote on Mon, 01 April 2013 00:41
On 01/04/2013 3:45 AM, David Rees wrote:
> When EPackageImpl.getEClassifiers().remove(EClassifier) is called, the
> underlying EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap
> does not have its corresponding entry deleted.
It's not updated when you rename something either, nor are things like
org.eclipse.emf.ecore.impl.EPackageImpl.eNameToEClassifierMap
>
>
> Am I using things somehow incorrectly?
Perhaps. These types of things aren't expected to be used on a model
that mutates and a model that's been used to create instances isn't
expected to mutate once it's used in that way.
> I know we can't change a metamodel once it's model is loaded, but I
> had assumed that we should be able to modify a loaded metamodel before
> we load the model.
Before it's used to create instances (with loading just being one of those).
>
> If we are using it correctly then it I guess the
> EPackageExtendedMetaDataImpl should be updated to register for
> notifications on eClassifiers so it can delete entries when needed.
What are you using extended meta data for? How are you using it in
combination with deleting classifiers from a package (or renaming them,
or deleting/renaming features in a class, all of which will have similar
issues). The list of all the things that are cached and affected by
arbitrary changes you make to the model is very long...
To be clear, we haven't used the metamodel yet to create model instances when we do the remove. It's something like this...
// load the metamodel
XMLResource resource = new XMIResourceImpl(metamodelURI);
resource.load(null);
// then get its package
EPackage epackage = resource.getContents().get(0);
// then delete a class from it, here I am just removing the first class, but we actually remove a few based on their name
epackage.getEClassifiers().remove(0);
// then try to load a model using that epackage
XMLResource resource = new XMLResourceImpl();
ExtendedMetaData extendedMetaData = BasicExtendedMetaData.INSTANCE;
extendedMetaData.putPackage(null, defaultEPackage);
resource.getDefaultLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
resource.getDefaultLoadOptions().put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE);
resource.getDefaultLoadOptions().put(XMLResource.OPTION_USE_LEXICAL_HANDLER, Boolean.TRUE);
ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResources().add(resource);
resource.load(null);
Ed Merks wrote on Mon, 01 April 2013 00:41
If you use this constructor you can flush the map (or create a new
instances) whenever you make these types of changes.
org.eclipse.emf.ecore.util.BasicExtendedMetaData.BasicExtendedMetaData(String,
Registry, Map<EModelElement, EAnnotation>)
Unfortunately simply replacing the BasicExtendedMetaData won't make a difference, because by default BasicExtendedMetaData.extendedMetaDataHolderCache is null so the EPackageExtendedMetaDataImpl is actually stored inside EPackageImpl.ePackageExtendedMetaData. So even a new BasicExtendedMetaData will still get the same EPackageExtendedMetaDataImpl for that package.
That said, if instead of using BasicExtendedMetaData.INSTANCE I use an instance of this simple subclass things seems to be work. Though I am not 100% sure why yet...
public class CacheUsingBasicExtendedMetaData extends BasicExtendedMetaData {
public CacheUsingBasicExtendedMetaData() {
super();
extendedMetaDataHolderCache = new HashMap<EModelElement, Object>();
}
}
I had thought in addition to introducing the CacheUsingBasicExtendedMetaData I would have to add a cache reset after the class deletes, but it works without doing that for some reason (and I don't like fixes that magically work .
Thanks for your help on this,
dave
|
|
|
Re: EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed [message #1031731 is a reply to message #1031364] |
Tue, 02 April 2013 06:05 |
Ed Merks Messages: 33142 Registered: July 2009 |
Senior Member |
|
|
David,
Comments below.
On 01/04/2013 6:19 PM, David Rees wrote:
> Ed Merks wrote on Mon, 01 April 2013 00:41
>> On 01/04/2013 3:45 AM, David Rees wrote:
>> > When EPackageImpl.getEClassifiers().remove(EClassifier) is called,
>> the > underlying
>> EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap > does not
>> have its corresponding entry deleted.
>> It's not updated when you rename something either, nor are things
>> like org.eclipse.emf.ecore.impl.EPackageImpl.eNameToEClassifierMap
>> >
>>
>> >
>> > Am I using things somehow incorrectly? Perhaps. These types of
>> things aren't expected to be used on a model that mutates and a model
>> that's been used to create instances isn't expected to mutate once
>> it's used in that way.
>> > I know we can't change a metamodel once it's model is loaded, but I
>> > had assumed that we should be able to modify a loaded metamodel
>> before > we load the model.
>> Before it's used to create instances (with loading just being one of
>> those).
>>
>> >
>> > If we are using it correctly then it I guess the >
>> EPackageExtendedMetaDataImpl should be updated to register for >
>> notifications on eClassifiers so it can delete entries when needed.
>> What are you using extended meta data for? How are you using it in
>> combination with deleting classifiers from a package (or renaming
>> them, or deleting/renaming features in a class, all of which will
>> have similar issues). The list of all the things that are cached and
>> affected by arbitrary changes you make to the model is very long...
>
>
> To be clear, we haven't used the metamodel yet to create model
> instances when we do the remove. It's something like this...
> // load the metamodel
> XMLResource resource = new XMIResourceImpl(metamodelURI);
> resource.load(null);
That's all very normal although this would only work well if the model
doesn't have relative references to other models.
> // then get its package
> EPackage epackage = resource.getContents().get(0);
> // then delete a class from it, here I am just removing the first
> class, but we actually remove a few based on their name
Are you using extended meta data in some way during this removal
process? I don't see how there would otherwise be stale cached
information in the model at this point unless there's more going on than
what you've shown here.
> epackage.getEClassifiers().remove(0);
> // then try to load a model using that epackage
> XMLResource resource = new XMLResourceImpl();
> ExtendedMetaData extendedMetaData =
> BasicExtendedMetaData.INSTANCE;
> extendedMetaData.putPackage(null, defaultEPackage);
> resource.getDefaultLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA,
> extendedMetaData);
> resource.getDefaultLoadOptions().put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE,
> Boolean.TRUE);
> resource.getDefaultLoadOptions().put(XMLResource.OPTION_USE_LEXICAL_HANDLER,
> Boolean.TRUE);
> ResourceSet resourceSet = new ResourceSetImpl();
> resourceSet.getResources().add(resource);
> resource.load(null);
>
> Ed Merks wrote on Mon, 01 April 2013 00:41
>> If you use this constructor you can flush the map (or create a new
>> instances) whenever you make these types of changes.
>>
>> org.eclipse.emf.ecore.util.BasicExtendedMetaData.BasicExtendedMetaData(String,
>> Registry, Map<EModelElement, EAnnotation>)
>
>
> Unfortunately simply replacing the BasicExtendedMetaData won't make a
> difference, because by default
> BasicExtendedMetaData.extendedMetaDataHolderCache is null so the
> EPackageExtendedMetaDataImpl is actually stored inside
> EPackageImpl.ePackageExtendedMetaData.
That's why I specifically mentioned that particular constructor.
> So even a new BasicExtendedMetaData will still get the same
> EPackageExtendedMetaDataImpl for that package.
> That said, if instead of using BasicExtendedMetaData.INSTANCE I use an
> instance of this simple subclass things seems to be work. Though I am
> not 100% sure why yet...
>
> public class CacheUsingBasicExtendedMetaData extends
> BasicExtendedMetaData {
> public CacheUsingBasicExtendedMetaData() {
> super();
> extendedMetaDataHolderCache = new HashMap<EModelElement,
> Object>();
> }
> }
>
> I had thought in addition to introducing the
> CacheUsingBasicExtendedMetaData I would have to add a cache reset
> after the class deletes, but it works without doing that for some
> reason (and I don't like fixes that magically work :).
Well, what you show avoids using the internally cached data, but from
you show, it's not clear what's causing the internally cached data to be
cached in the first place...
>
>
> Thanks for your help on this,
>
> dave
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Re: EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed [message #1034759 is a reply to message #1031731] |
Fri, 05 April 2013 21:33 |
David Rees Messages: 47 Registered: September 2012 |
Member |
|
|
Ed Merks wrote on Tue, 02 April 2013 02:05David,
That's all very normal although this would only work well if the model
doesn't have relative references to other models.
...
Are you using extended meta data in some way during this removal
process? I don't see how there would otherwise be stale cached
information in the model at this point unless there's more going on than
what you've shown here.
...
Well, what you show avoids using the internally cached data, but from
you show, it's not clear what's causing the internally cached data to be
cached in the first place...
It looks like the EMF BasicValidator class accesses the extended metadata to get the DocumentRoot as part of loading the metamodel. In fact, it accesses ExtendedMetaData.INSTANCE (so there is no way to override it). Here is the stack:
Thread [main] (Suspended)
BasicExtendedMetaData$EPackageExtendedMetaDataImpl.getType(String) line: 2146
BasicExtendedMetaData.getType(EPackage, String) line: 108
BasicExtendedMetaData.getDocumentRoot(EPackage) line: 130
FeatureMapUtil$BasicValidator.<init>(EClass, EStructuralFeature) line: 1555
FeatureMapUtil.getValidator(EClass, EStructuralFeature) line: 1706
BasicFeatureMap.<init>(InternalEObject, int) line: 48
AnyTypeImpl.getMixed() line: 90
SAXXMIHandler(XMLHandler).<init>(XMLResource, XMLHelper, Map<?,?>) line: 438
SAXXMIHandler(XMIHandler).<init>(XMLResource, XMLHelper, Map<?,?>) line: 49
SAXXMIHandler.<init>(XMLResource, XMLHelper, Map<?,?>) line: 33
XMILoadImpl.makeDefaultHandler() line: 33
XMILoadImpl(XMLLoadImpl).load(XMLResource, InputStream, Map<?,?>) line: 139
XMIResourceImpl(XMLResourceImpl).doLoad(InputStream, Map<?,?>) line: 253
XMIResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1529
XMIResourceImpl(ResourceImpl).load(Map<?,?>) line: 1308
It's also accessed by the SAXMLHandler in createDocumentRoot. In that case it uses the BasicExtendedMetaData that was passed to it in the load options. So by overriding it in the load the user is actually causing two different ExtendedMetaDatas to be used depending on the call path. That doesn't seem correct, does it? Even though I think that is what is causing my code to magically work when I switch to my own ExtendedMetaData instance (the caching that causes the problem is done in the ExtendedMetaData.INSTANCE rather than mine).
Thread [main] (Suspended (breakpoint at line 2146 in BasicExtendedMetaData$EPackageExtendedMetaDataImpl))
BasicExtendedMetaData$EPackageExtendedMetaDataImpl.getType(String) line: 2146
BasicExtendedMetaData.getType(EPackage, String) line: 108
BasicExtendedMetaData.getDocumentRoot(EPackage) line: 130
SAXXMIHandler(XMLHandler).createDocumentRoot(String, String, String, EFactory, boolean) line: 1379
SAXXMIHandler(XMIHandler).createDocumentRoot(String, String, String, EFactory, boolean) line: 108
SAXXMIHandler(XMLHandler).createObjectByType(String, String, boolean) line: 1326
SAXXMIHandler(XMLHandler).createTopObject(String, String) line: 1475
SAXXMIHandler(XMLHandler).processElement(String, String, String) line: 1026
SAXXMIHandler(XMIHandler).processElement(String, String, String) line: 77
SAXXMIHandler(XMLHandler).startElement(String, String, String) line: 1008
SAXXMIHandler(XMLHandler).startElement(String, String, String, Attributes) line: 719
SAXXMIHandler(XMIHandler).startElement(String, String, String, Attributes) line: 163
SAXParserImpl$JAXPSAXParser(AbstractSAXParser).startElement(QName, XMLAttributes, Augmentations) line: 501
XMLDTDValidator.startElement(QName, XMLAttributes, Augmentations) line: 767
XMLDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanStartElement() line: 1363
XMLDocumentScannerImpl$ContentDriver.scanRootElementHook() line: 1315
XMLDocumentScannerImpl$ContentDriver(XMLDocumentFragmentScannerImpl$FragmentContentDriver).next() line: 3104
XMLDocumentScannerImpl$PrologDriver.next() line: 921
XMLDocumentScannerImpl.next() line: 647
XMLDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanDocument(boolean) line: 511
XIncludeAwareParserConfiguration(XML11Configuration).parse(boolean) line: 808
XIncludeAwareParserConfiguration(XML11Configuration).parse(XMLInputSource) line: 737
SAXParserImpl$JAXPSAXParser(XMLParser).parse(XMLInputSource) line: 119
SAXParserImpl$JAXPSAXParser(AbstractSAXParser).parse(InputSource) line: 1205
SAXParserImpl$JAXPSAXParser.parse(InputSource) line: 522
SAXParserImpl(SAXParser).parse(InputSource, DefaultHandler) line: 395
XMILoadImpl(XMLLoadImpl).load(XMLResource, InputStream, Map<?,?>) line: 175
XMIResourceImpl(XMLResourceImpl).doLoad(InputStream, Map<?,?>) line: 253
XMIResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1529
XMIResourceImpl(ResourceImpl).load(Map<?,?>) line: 1308
Thanks,
dave
|
|
|
Re: EPackageImpl.ePackageExtendedMetaData.nameToClassifierMap not updated when classifier removed [message #1034960 is a reply to message #1034759] |
Sat, 06 April 2013 05:14 |
Ed Merks Messages: 33142 Registered: July 2009 |
Senior Member |
|
|
David,
Comments below.
On 05/04/2013 11:33 PM, David Rees wrote:
> Ed Merks wrote on Tue, 02 April 2013 02:05
>> David,
>> That's all very normal although this would only work well if the
>> model doesn't have relative references to other models.
>> ...
>> Are you using extended meta data in some way during this removal
>> process? I don't see how there would otherwise be stale cached
>> information in the model at this point unless there's more going on
>> than what you've shown here.
>> ...
>> Well, what you show avoids using the internally cached data, but from
>> you show, it's not clear what's causing the internally cached data to
>> be cached in the first place...
>
>
> It looks like the EMF BasicValidator class accesses the extended
> metadata to get the DocumentRoot as part of loading the metamodel. In
> fact, it accesses ExtendedMetaData.INSTANCE (so there is no way to
> override it). Here is the stack:
>
> Thread [main] (Suspended)
> BasicExtendedMetaData$EPackageExtendedMetaDataImpl.getType(String)
> line: 2146
> BasicExtendedMetaData.getType(EPackage, String) line: 108
> BasicExtendedMetaData.getDocumentRoot(EPackage) line: 130
> FeatureMapUtil$BasicValidator.<init>(EClass, EStructuralFeature)
> line: 1555
> FeatureMapUtil.getValidator(EClass, EStructuralFeature) line: 1706
> BasicFeatureMap.<init>(InternalEObject, int) line: 48
> AnyTypeImpl.getMixed() line: 90
Sure for the model of the XMLTypePackage.
> SAXXMIHandler(XMLHandler).<init>(XMLResource, XMLHelper, Map<?,?>)
> line: 438
> SAXXMIHandler(XMIHandler).<init>(XMLResource, XMLHelper, Map<?,?>)
> line: 49
> SAXXMIHandler.<init>(XMLResource, XMLHelper, Map<?,?>) line: 33
> XMILoadImpl.makeDefaultHandler() line: 33
> XMILoadImpl(XMLLoadImpl).load(XMLResource, InputStream, Map<?,?>)
> line: 139
> XMIResourceImpl(XMLResourceImpl).doLoad(InputStream, Map<?,?>)
> line: 253
> XMIResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1529
> XMIResourceImpl(ResourceImpl).load(Map<?,?>) line: 1308
>
>
>
> It's also accessed by the SAXMLHandler in createDocumentRoot.
Yes for the model of the instance being loaded.
> In that case it uses the BasicExtendedMetaData that was passed to it
> in the load options. So by overriding it in the load the user is
> actually causing two different ExtendedMetaDatas to be used depending
> on the call path. That doesn't seem correct, does it?
We'd not allow more than one instance ever to be created if it wasn't
okay to do so.
> Even though I think that is what is causing my code to magically work
> when I switch to my own ExtendedMetaData instance (the caching that
> causes the problem is done in the ExtendedMetaData.INSTANCE rather
> than mine).
>
> Thread [main] (Suspended (breakpoint at line 2146 in
> BasicExtendedMetaData$EPackageExtendedMetaDataImpl))
> BasicExtendedMetaData$EPackageExtendedMetaDataImpl.getType(String)
> line: 2146
> BasicExtendedMetaData.getType(EPackage, String) line: 108
> BasicExtendedMetaData.getDocumentRoot(EPackage) line: 130
> SAXXMIHandler(XMLHandler).createDocumentRoot(String, String,
> String, EFactory, boolean) line: 1379
> SAXXMIHandler(XMIHandler).createDocumentRoot(String, String,
> String, EFactory, boolean) line: 108
> SAXXMIHandler(XMLHandler).createObjectByType(String, String,
> boolean) line: 1326
> SAXXMIHandler(XMLHandler).createTopObject(String, String) line: 1475
> SAXXMIHandler(XMLHandler).processElement(String, String, String)
> line: 1026
> SAXXMIHandler(XMIHandler).processElement(String, String, String)
> line: 77
> SAXXMIHandler(XMLHandler).startElement(String, String, String)
> line: 1008
> SAXXMIHandler(XMLHandler).startElement(String, String, String,
> Attributes) line: 719
> SAXXMIHandler(XMIHandler).startElement(String, String, String,
> Attributes) line: 163
> SAXParserImpl$JAXPSAXParser(AbstractSAXParser).startElement(QName,
> XMLAttributes, Augmentations) line: 501
> XMLDTDValidator.startElement(QName, XMLAttributes, Augmentations)
> line: 767
> XMLDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanStartElement()
> line: 1363
> XMLDocumentScannerImpl$ContentDriver.scanRootElementHook() line: 1315
> XMLDocumentScannerImpl$ContentDriver(XMLDocumentFragmentScannerImpl$FragmentContentDriver).next()
> line: 3104
> XMLDocumentScannerImpl$PrologDriver.next() line: 921
> XMLDocumentScannerImpl.next() line: 647
> XMLDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanDocument(boolean)
> line: 511
> XIncludeAwareParserConfiguration(XML11Configuration).parse(boolean) line:
> 808
> XIncludeAwareParserConfiguration(XML11Configuration).parse(XMLInputSource)
> line: 737
> SAXParserImpl$JAXPSAXParser(XMLParser).parse(XMLInputSource) line:
> 119
> SAXParserImpl$JAXPSAXParser(AbstractSAXParser).parse(InputSource)
> line: 1205
> SAXParserImpl$JAXPSAXParser.parse(InputSource) line: 522
> SAXParserImpl(SAXParser).parse(InputSource, DefaultHandler) line: 395
> XMILoadImpl(XMLLoadImpl).load(XMLResource, InputStream, Map<?,?>)
> line: 175
> XMIResourceImpl(XMLResourceImpl).doLoad(InputStream, Map<?,?>)
> line: 253
> XMIResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1529
> XMIResourceImpl(ResourceImpl).load(Map<?,?>) line: 1308
When I set a breakpoint is EPackageImpl.setExtendedMetaData and I load a
*.ecore resource in the Sample Ecore Editor, I don't see that loading
the model causes this to be called on the model being loaded. I.e., in
your logic
XMLResource resource = new XMIResourceImpl(metamodelURI);
resource.load(null);
// then get its package
EPackage epackage = resource.getContents().get(0);
// then delete a class from it, here I am just removing the first class,
but we actually remove a few based on their name
epackage.getEClassifiers().remove(0);
I don't think it's called before your "// then delete a class" logic but
rather I suspect something you're doing in that logic is causing it to
be called.
>
>
> Thanks,
> dave
Ed Merks
Professional Support: https://www.macromodeling.com/
|
|
|
Goto Forum:
Current Time: Fri Apr 26 19:23:28 GMT 2024
Powered by FUDForum. Page generated in 0.03881 seconds
|