Community
Participate
Working Groups
It would be nice if a generator fragment could obtain the generated and referenced GenModels from the generator framework for all EPackages referenced by the grammar. This would allow the fragment to generate code which depends on the code generated by EMF (e.g. the generated EClasses or the XyzPackage.Literals interface). Although none of the generator fragments provided by Xtext require any information contained in the GenModel files I think this is a quite common use case for custom generator fragments. As a workaround we currently implemented our own EcoreGeneratorFragment subclass which makes this information available statically for other fragments to use.
I might need this capability for the new serializer. Generated code that purely works with EObject + EMF's reflection isn't exactly readable.
I propose to register GenModels like this: ---- protected void registerGenmodel(GenModel genModel) { Map<String, URI> registry = EcorePlugin.getEPackageNsURIToGenModelLocationMap(); URI uri = genModel.eResource().getURI(); for (GenPackage pkg : genModel.getGenPackages()) registry.put(pkg.getEcorePackage().getNsURI(), uri); } ---- since org.eclipse.emf.ecore.plugin.EcorePlugin.getEPackageNsURIToGenModelLocationMap() refers to a static singleton all GeneratorFragments (and WorkflowCOmponents!) can read/populate the registry. Furhtermore, the access the GenModels from within Xtend/Xpand, I propose this API ---- cached GenPackage getGenPackage(EPackage pkg): JAVA org.eclipse.xtext.generator.GenModelAccess.getGenPackage(org.eclipse.emf.ecore.EPackage); cached GenClassifier getGenClassifier(EClassifier classifier): JAVA org.eclipse.xtext.generator.GenModelAccess.getGenClassifier(org.eclipse.emf.ecore.EClassifier); cached GenFeature getGenFeature(EStructuralFeature feature): JAVA org.eclipse.xtext.generator.GenModelAccess.getGenFeature(org.eclipse.emf.ecore.EStructuralFeature); GenClass getGenClass(EClass cls): (GenClass) cls.getGenClassifier(); GenDataType getGenDataType(EDataType dt): (GenDataType) dt.getGenClassifier(); GenEnum getGenEnum(EEnum en): (GenEnum) en.getGenClassifier(); ----
We need to make sure that it doesn't break migrated 2.0-clients and I'ld only want to see the 'cached' modifiers if it really makes a difference.
What about the genmodels that are created from the generated EPackages of a grammar? Would you add them to the global singleton on the fly? Why don't we expose the genmodels from the EcoreGeneratorFragment by means of a getter and use MWE2 to wire this one together with the SerializerFragment? I'd prefer to use the same pattern for the GenModelAccess as for the Naming instance.
(In reply to comment #4) > I'd prefer to use the same pattern for the GenModelAccess as for the Naming > instance. Never mind. What I'd actually prefer would be an explicit parameter in AbstractGeneratorFragment.getParameters(Grammar).
(In reply to comment #5) > (In reply to comment #4) > > I'd prefer to use the same pattern for the GenModelAccess as for the Naming > > instance. > > Never mind. What I'd actually prefer would be an explicit parameter in > AbstractGeneratorFragment.getParameters(Grammar). I suppose a setter would be used to "share" parameters. Something like the EValidator's context Map<?,?> might be good enough. This design would then exclude generic workflow components. So what about the custom classes generator? (In one of our projects I've created a corresponding fragment.) Another use case which I think should be considered: File extensions. These are currently only passed on to the implicit ui fragment. These could be useful to other fragments as well.
(In reply to comment #4) > What about the genmodels that are created from the generated EPackages of a > grammar? Would you add them to the global singleton on the fly? I think I misunderstood the proposal in comment #2. registerGenmodel is not a new method in the StandaloneSetup but something internal to EcoreGeneratorFragment, isn't it? If yes, than I'm fine with the proposed API.
Thx for the feeback… I'll try to give my response some structure: (1) Components vs. Fragments There are mwe.WorkflowComponents and xtext.GeneratorComponents that might want to access or contribute a genmodel. Therefore I think the mechanisms to do this should not be limited to either of theses concepts. The use case that Knut mentioned in comment #6 (make file extensions accessible) is different, because a file extension belongs to a language (represented by xtext.Generator) and a genmodel is not tied to a language and should be accessible wherever the coresponding Ecore model is accessed. (2) Contributing (registering) Genmodels could/should be done by Maybe I rushed forward too much when posting the proposals. Let's take a step back. The use cases that I'm seeing are: - GenModels from the file system should be accessible. - GenModels registerd via plugin.xml should be accessible, when MWE runs in OSGi-mode? - GenModels created by xtext.EcoreGeneratorFragment should be accessibe. - GenModels created by a workflow component should be accessibe. The current version of mwe.util.EcoreGenerator does not create a GenModel, but the version of it that I originally implemented did. I like the idea of not relying on EMF's GenModel-reload-mechanism. - GenModels should be accessible by WorkflowComponents - GenModels should be accesisble by generator-Fragments (our main issue) This could potentialy allow to automatically collect the GenModel for EcoreGeneratorFragment.usedGenModels. Thoughts about using EMF's static GenModel registry vs. using MWE to wire together some components/beans: - I like the idea to have an implementation symmetric to EMF's EPackage registry. - I like the idea than an already populated GenModel registry can be accessed, if it exists. - I don't like the idea that a user has to configure the genmodel for each singe place of usage. I think its perfectly fine if the user ensures that a proper genmodel is created/registered somewhere. Control over where it is bein accessed doen't provide any value (only effor and confusion), because a configured Ecore model always implies which GenModel is to be used. Thoughts on the implementation: - EcoreGeneratorFragment should register it's genmodels at EcorePlugin.getEPackageNsURIToGenModelLocationMap() - StandaloneSetup should be able to register GenModel-files in EcorePlugin.getEPackageNsURIToGenModelLocationMap(). This implementation would be symmetric to StandaloneSetup.addRegisterEcoreFile(String). - mwe.ecore.EcoreGenerator could also register it's genmodel, but I'm undecided if it should. (In reply to comment #4) > Why don't we expose the genmodels from the EcoreGeneratorFragment by means of a > getter and use MWE2 to wire this one together with the SerializerFragment? (In reply to comment #5) > (In reply to comment #4) > > I'd prefer to use the same pattern for the GenModelAccess as for the Naming > > instance. > > Never mind. What I'd actually prefer would be an explicit parameter in > AbstractGeneratorFragment.getParameters(Grammar). We would have to pass in a list of GenPackages that we would have to carry through all DEFINE-blocks in the template. That adds a lot of noise to the code. I don't see the benefit of handing in the GenPackages explicitly, since logically there can only be one GenPackage per EPackage, one GenClass per EClass. etc. So I think it's perfectly fine to have an extension-method that accesses EcorePlugin.getEPackageNsURIToGenModelLocationMap() directly. (In reply to comment #6) > This design would then exclude generic workflow components. So what about the > custom classes generator? (In one of our projects I've created a corresponding > fragment.) good point. (In reply to comment #6) > Another use case which I think should be considered: File extensions. These are > currently only passed on to the implicit ui fragment. These could be useful to > other fragments as well. I think file extensions are different, because they belong to an Xtext-Language, which is represented by xtext.generator.Generator in the workflow. A Fragment should be able to access it's containing Generator and therby reach that kind of information. A GenModel on the other hand belongs to an Ecore model and should be available everywhere where the Ecore model is available. These places are all Workflow-Instructions that are executed after the GenModel has been created/registered. (In reply to comment #7) > (In reply to comment #4) > > What about the genmodels that are created from the generated EPackages of a > > grammar? Would you add them to the global singleton on the fly? > > I think I misunderstood the proposal in comment #2. > registerGenmodel is not a new method in the StandaloneSetup but something > internal to EcoreGeneratorFragment, isn't it? If yes, than I'm fine with the > proposed API. yes, that's how I have it in mind. I thinkg the StandaloneSetup should have such a method too hat takes a GenModel's file name as a parameter.
(In reply to comment #8) > Thx for the feeback… I'll try to give my response some structure: > > (1) Components vs. Fragments > There are mwe.WorkflowComponents and xtext.GeneratorComponents that might want > to access or contribute a genmodel. Therefore I think the mechanisms to do this > should not be limited to either of theses concepts. The use case that Knut > mentioned in comment #6 (make file extensions accessible) is different, because > a file extension belongs to a language (represented by xtext.Generator) and a > genmodel is not tied to a language and should be accessible wherever the > coresponding Ecore model is accessed. > > (2) Contributing (registering) Genmodels > could/should be done by never mind this part of my last message. It's a draft and destined for /dev/null
We all hate global state, don't we? But the alternatives are also not compelling. When running within Equinox the maps in EcorePlugin should be modified only by EMF's extension points. So relying on the EcorePlugin maps really means that we'll not be able to run the same code within Equinox if we wan to process models from the workspace (they should never go into the workbench registries). Anyway, I don't see this requirement in the near future and for the sake of simplicity I am ok with using EcorePlugin.getEPackageNsURIToGenModelLocationMap(). An alternative would be to have our own static Map, but as we also already use the other registries and therefore suffer from the related problems doing it differently only in this case would be a half-baked thing. +1 for populating and using EcorePlugin.getEPackageNsURIToGenModelLocationMap() @Ed: Do you have any concerns with modifying and accessing EcorePlugin.getEPackageNsURIToGenModelLocationMap() in a standalone (i.e. non-equinox) scenario?
Using EcorePlugin.getEPackageNsURIToGenModelLocationMap in stand-alone via direct updates is fine.
I've pushed some updates: (1) The EcoreGeneratorFragemnt now registers its GenModels: http://git.eclipse.org/c/tmf/org.eclipse.xtext.git/commit/?id=5a4f82d7f9d8ff89029c7035937d2b80feab07aa (2) A utility class for convenient access of the GenModel: http://git.eclipse.org/c/tmf/org.eclipse.xtext.git/commit/?id=1d211fc7878462bc334f41234e8b1766cace13cf There are three different kinds of access: a) get the GenPackge/GenClassifier/GenFeature for a EPackage/EClass/EStructurslFeature b) get the integer literal (such as MyPackage.MY_CLASS or MyPackage.MY_CLASS__MY_FEATURE) for an EClassifier or EStructuralFeature. c) get the type literal (such as MyPackage.eINSTANCE, MyPackage.Literals.MyClass or MyPackage.Literals.MyClass_MyFeature) for an EPackage, EClassifier or EStruturalFeature. Things that are still open: - allow to register GenModels that exists as files. - should mwe2.ecore.EcoreGenerator automatically register its GenModels? That would be convenient, but not strictly necessary, since they always exist as files, too.
(In reply to comment #12) > Things that are still open: > - allow to register GenModels that exists as files. Intuitively I would add a method to mwe.utils.StandaloneSetup, symmetrically to addRegisterEcoreFile(String). However, for this I would need to introduce a dependency from mwe.util to emf.codegen. Any objections? Plan B would be to create a bean named GenModelSetup in bundle mwe2.lib (and package mwe2.ecore). Bundle mew2.lib already depends on emf.codegen. Opinions?
(In reply to comment #13) > Intuitively I would add a method to mwe.utils.StandaloneSetup, symmetrically to > addRegisterEcoreFile(String). > > However, for this I would need to introduce a dependency from mwe.util to > emf.codegen. Any objections? I kept the dependency optional and added a patch to bug 343398.
now that bug 343398 is fixed I consider this one as fixed, too.