Use the same project for EMF model and edit code? - eclipse-emf

Can I somehow use the same Eclipse plug-in project for both a generated EMF model and the corresponding generated EMF Edit code?
Normally these two components reside in two different projects, the EMF Edit one with the suffix .edit to its name. I find this superfluous, since there is so little code in the Edit project, and it is so closely related to the model code.
I have tried setting both the modelDirectory and the editDirectory Gen Model attributes to (different) directories in the same project, but that seems to lead to endless confusion and build problems. I think maybe the two generation steps overwrite each others project setting files.

After some more experimentation it seems like it works fine to have EMF and EMF Edit generated code in the same project.
The things I had to do to make it work are the following:
Setting the genmodel property modelDirectory and editDirectory to the same directory. Otherwise I got a build error saying "The type ... is already defined in ...".
Setting the genmodel property bundleManifest="false". Otherwise the plug-in ID is overwritten by the generation process.
Apart from this I also set updateClasspath="false" to avoid that the generation process messes around with that.
The automatic updates to the manifest and plugin.xml files seem to be the following:
Set plug-in ID
Add exported packages
Add EMF extensions to plugin.xml
2 and 3 needs to be performed manually if they are desired. That would involve adding entries to plugin.xml similar to these:
<extension point="org.eclipse.emf.ecore.generated_package">
<!-- #generated model -->
<package
uri="somePackage"
class="somePackage.SomePackage"
genModel="model/model.xcore"/>
</extension>
<extension point="org.eclipse.emf.edit.itemProviderAdapterFactories">
<!-- #generated model -->
<factory
uri="somePackage"
class="somePackage.someClass"
supportedTypes=
"org.eclipse.emf.edit.provider.IEditingDomainItemProvider
org.eclipse.emf.edit.provider.IStructuredItemContentProvider
org.eclipse.emf.edit.provider.ITreeItemContentProvider
org.eclipse.emf.edit.provider.IItemLabelProvider
org.eclipse.emf.edit.provider.IItemPropertySource"/>
</extension>

Related

Pre-Processing C++ file using MSBuild and Visual Studio 2012+

I have a series of standard cpp files and each of these files contain a file-specific #include statement. However, the content of those included files must be populated by a pre-processing tool prior to invoking the standard C++ compiler.
The tricky part is that I want this to be fully integrated into Visual Studio using MSBuild. Therefore, when I bring up Visual Studio's Property Window on a cpp file, I want to see all the standard C++ compiler options and, ideally, some Custom Properties controlling the pre-processor tool. As a OOP analogy, I want my build tool to inherit everything from the standard CL MSBuild Rule, and add some Custom Properties & Build Steps to it.
I have successfully done this through an extremely laborious process of basically creating a Custom MSBuild Rule and Copy/Paste most of the C++ Options into my Custom Rule. Finally, I then pass along the million C++ Options to the standard C++ compiler through the CommandLineTemplate entry in my MSBuild .props file. It's ridiculously complicated and the C++ options don't automatically get updated as I update Visual Studio.
I can find plenty of examples of Custom MSBuild Rules, but I haven't been able to find one where it piggybacks onto an existing one.
Not a lot of love for MSBuild, I take it...
Anyway, after years of going back and forth on that one, I finally found something, soon after I posted my question. The key was to search for "extending" existing Rule which, apparently, I hadn't tried before.
Usually, when you create a Build Customization in VS, you end up with 3 files:
MyCustomBuild.xml:
Contains the Properties & Switches, as shown on the VS's Property Sheet.
MyCustomBuild.props:
Contains default values for those Properties. They can be made conditional through the use of the Condition attribute.
MyCustomBuild.targers:
Contains a line to load up your xml and the Target/Task entries.
So the first part was to extend the existing C/C++ Properties as shown in Visual Studio. I found this link, which finally gave me something to work with:
https://github.com/Microsoft/VSProjectSystem/blob/master/doc/extensibility/extending_rules.md
Here's the xml bit.
<Rule
Name="RuleToExend"
DisplayName="File Properties"
PageTemplate="generic"
Description="File Properties"
OverrideMode="Extend"
xmlns="http://schemas.microsoft.com/build/2009/properties">
<!-- Add new properties, data source, categories, etc -->
</Rule>
Name attribute:
The Name attribute must match the rule being extended. In this case, I wanted to extend the CL rule, so I set that attribute = "CL".
DisplayName attribute:
This is optional. When provided, it will overwrite the tool's name seen on the Property Sheet. In this case, the tool name shown is "C/C++". I can change it to show "My C/C++" by setting this attribute.
PageTemplate attribute:
If this attribute is provided, it must match the overwritten rule's value. In this case, it would be "tool". Just leaving it out seems to work fine. I suspect this could be needed if 2 rules had the same name, but a different template. You could use this to clarify which one you wanted to extend.
Description attribute:
Optional. I don't know where that even shows up within the VS GUI. Maybe it's just for documenting the xml file.
OverrideMode attribute:
This is an important one! It can be set to either "Extend" or "Replace". In my case, I chose "Extend".
xmlns attribute:
Required. Doesn't work properly if not present.
As the link suggest, you can then provide the properties, data source and categories. Keep in mind that categories are usually displayed in the order they appear in the xml file. Since I was extending an existing Rule, my custom categories would all show up after the standard C/C++ categories. Given that my tool is for pre-processing the files, I would have preferred having my custom options at the top of the Property Sheet. But I couldn't find way around that.
Note that you do NOT need the ItemType/FileExtension or ContenType Properties, typically found for custom Rules.
So once I entered all of that, my custom pre-processing options showed up alongside the standard C/C++ properties on the Property Sheet. Note that all these new properties would be attached to the "ClCompile" Item list, with all the other C/C++ properties.
The next step was to update the .props file. I'm not going to get into it since it's pretty much standard when create these custom build Rules. Just know that you need to set them using the "ClCompile" Item, as mentioned above.
The final step was to get the .targets file to do what I wanted.
The first part was to "import" (not really an import entry) the custom Rule through the typical entry:
<ItemGroup>
<PropertyPageSchema Include="$(MSBuildThisFileDirectory)MyCustomBuild.xml" />
</ItemGroup>
Then I needed to pre-process every source file. Ideally, it would have been nicer to pre-process a file and then compile it - one file a time. I could have done this by overwriting the "ClCompile" target within my own .targets file. This Target is defined under the "Microsoft.CppCommon.targets" file (location under "C:\Program Files (x86)" varies, depending on the VS version). I basically could have Cut & Pasted the whole Target into my file, then add my pre-processing task code before the "CL" Task. I also would have needed to convert the Target into a Target Batch, by adding an "Outputs=%(ClCompile.Identity)" attribute to the "ClCompile" Target. Without this, my pre-processing task would have ran on all files before moving on to the "CL" task, bringing me back to square one. Finally, I would have needed to deal with Pre-Compiled Header files, since they need to be compiled first.
All of this was just too much of a pain. So I selected the simpler option of defining a Target which looks like this:
<Target Name="MyPreProcessingTarget"
Condition="'#(ClCompile)' != ''"
Outputs ="%(ClCompile.Identity)"
DependsOnTargets="_SelectedFiles"
BeforeTargets="ClCompile">
There are a number of attributes defined but the most important one is the BeforeTargets="ClCompile" attribute. This is what forces this target to execute before the cpp files are compiled.
I also chose to do a Target Batch processing here [Outputs ="%(ClCompile.Identity)"] because it was just easier to do what I wanted to do, if I assumed to have 1 file being processed at a time, in my Target.
The attribute DependsOnTargets="_SelectedFiles" is used to know if a GUI user has some selected file within VS Solution Explorer. If so, the files will be stored in the #(SelectedFiles) Item List (generated by the "_SelectedFiles" Target). Typically, when selecting specific files within the Solution Explorer and choosing to compile them, VS will forcefully compile them even if they are up-to-date. I wanted to preserve that functionality for the automatically-generated pre-processed include files, and forcefully regenerate them as well, for those selected files. So I added this block:
<ItemGroup Condition="'#(SelectedFiles)' != ''">
<IncFilesToDelete Include="%(ClCompile.Filename)_pp.h"/>
</ItemGroup>
<Delete
Condition="'#(IncFilesToDelete)' != ''"
Files="%(IncFilesToDelete.FullPath)" />
Note that the automatically-generated include files are named SourceFileName_pp.h. By deleting those files, my pre-processing Task will forcefully re-generate them.
Next, I build a new Item list from the "ClCompile" Item list, but with the "_pp.h" versions of the files. I do so with the following code:
<ItemGroup>
<PPIncFiles
Condition="'#(ClCompile)' != '' and '%(ClCompile.ExcludedFromBuild)' != 'true'"
Include="%(ClCompile.Filename)_pp.h" />
</ItemGroup>
The final part is a little uglier.
In order to run my pre-processing exe, I use the standard "Exec" Task. But I obviously only want to run it if the source file is newer than the generated file. I do so by storing the well-known metadata "ModifiedTime" of the source file, and the generated file into a couple of dynamic Properties. But I can't use the ModifiedTime metadata directly, as it's not an comparable value. So I used the following code, which I have found on StackOverflow here:
Comparing DateTime stamps in Msbuild
<PropertyGroup>
<SourceFileDate>$([System.DateTime]::Parse('%(ClCompile.ModifiedTime)').Ticks)</SourceFileDate>
<PPIncFileDate Condition="!Exists(%(PPIncFiles.Identity))">0</PPIncFileDate>
<PPIncFileDate Condition="Exists(%PPIncFiles.Identity))">$([System.DateTime]::Parse('%(PPIncFiles.ModifiedTime)').Ticks)</PPIncFileDate>
</PropertyGroup>
Note that I can store the timestamps in Properties, given that the Item Lists only contain one Item per Target Pass, because of Target Batching.
Finally, I can invoke my pre-processor using the "Exec" Task, as follows:
<Exec
Condition="'#(PPIncFiles)' != '' and $(SourceFileDate) > $(PPIncFileDate)"
Command="pptool.exe [options] %(ClCompile.Identity)" />
Supplying the options was yet, another headache.
Typically, the switches as defined under the xml file are just passed to a "CommandLineTemplate" metadata under the .props file using [OptionName]. This will pass the "Switch" attribute of the Property defined under the xml file. But that implies defining your own TaskName item, made from a TaskFactory, under the .targets file. But in my case, I was just using the existing "Exec" Task, which doesn't know anything about my custom Properties. I didn't know how to retrieve the "Switch" attribute in this case, and what seems to be available is just whatever the "Name" attribute contains. Luckily, a Property has both a Name and a DisplayName. The DisplayName is what the GUI user sees. So I just copied the "Switch" value into the "Name" value, when defining the Properties under the xml file. I could then pass the option to the Exec Task using something like:
<Exec
Condition="'#(PPIncFiles)' != '' and $(SourceFileDate) > $(PPIncFileDate)"
Command="pptool.exe %(ClCompile.Option1) %(ClCompile.Option2)... %(ClCompile.Identity)" />
Where I defined all my Properties as "EnumProperty", with an "EnumValue" having Name="" for disabled options, and other EnumValue having Name="switch" for the others. Not very elegant, but I didn't know a way around this.
Finally, it is recommended that when automatically generating files, the .targets file should also include a way to clean them up when the user Cleans up the Project. That's pretty standard but I'll include it here for convenience.
<PropertyGroup>
<CleanDependsOn>$(CleanDependsOn);PPIncCleanTarget</CleanDependsOn>
</PropertyGroup>
<Target Name="PPIncCleanTarget" Condition ="'#(ClCompile)' != ''">
<ItemGroup>
<PPIncFilesToDelete Include="%(ClCompile.Filename)_pp.h" />
</ItemGroup>
<Delete Files="%(PPIncFilesToDelete.FullPath)" Condition="'#(PPIncFilesToDelete)' != ''"/>
</Target>

List all available models in EMF application

I'm working on a project consisting of two Eclipse plugin projects. One is an EMF project and contains the metamodel for the application. The other one is the acctual plugin working on that metamodel.
I'm now looking for a way to list all types of models available in the metamodel project. Since I basically need all generated classes I could use reflections to iterate through the metamodel package but I'd prefer an easier way if there is one.
The models are already listed as extensions in the plugin.xml like this:
<plugin>
<extension point="org.eclipse.emf.ecore.generated_package">
<package
uri="MyModel"
class="org.myproject.metamodel.MyModel.MyModelPackage"
genModel="model/MetaModel.genmodel"/>
</extension>
</plugin>
where the class MyModelPackage extends EPackage and org.myproject.metamodel.MyModel also contains all the other generated classes I need to list. I'm guessing that I can use that information but I still don't know how.
Update
The project I'm working on is based on EMFStore. Running it offers the EMFStore perspective. If I have the Navigator view with a project I can right click on that project and select New Model Element. This opens a dialog where all the model elements from my metamodel are listed so it is possible. It must be done somewhere in EMFStore or one of it's dependencies. I looked through the source code but can't seem to find where it's done.
The plugin.xml of the project org.eclipse.emf.emfstore.perspective refers to the class org.eclipse.emf.emfstore.emfperspective.EMFStorePerspective which I can't find in the sources. I imported the project via the Eclipse Import Plug-Ins and Fragments functionality and it has no source folder. In the EMFStore git repositories I can't even find that project.
Update
I now got the registry that contains the generated packages using EPackage.Registry.INSTANCE. Unfortunately it contains more than the EPackages from the one project containing the metadata (org.myproject.metamodel). Now I'm just looking for a proper way to filter it, but still can't get the hang of it.
Update
As the filtering is not part of my original question I accepted the answer by #SpaceTrucker. For those who are curious, this is how I've done it now:
Registry registry = EPackage.Registry.INSTANCE;
for (String key : new HashSet<String>(registry.keySet())) {
EPackage ePackage = registry.getEPackage(key);
if (ePackage.getClass().getName().startsWith("org.myproject.metamodel")) {
//do stuf
}
}
I found no way to filter for the project but luckily all the packages start with the same prefix.
EPackages may be registered via an EPackage.Registry. There seems to be a globally used instance available via ECorePlugin.getDefaultRegistryImplementation(). However I'm not 100% sure on that.
MoDisco comes with a EMF Model Browser, where you are also able to select any registered EMF model. So you also could have a look at those sources.

Merging a resource from another Assembly in Silverlight

I added a Resource Dictionary named ResourceDictionary1 to my silverlight project.
I also added a Silverlight Class Library to my project named OtherAssembly, then in this new assembly I added a new Resource Dictionary named ResourceDictionary2:
In my original project I'm trying to merge both dictionaries in MainPage.xaml:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyResourceDictionary1.xaml" />
<ResourceDictionary Source="/OtherAssembly;component/MyResourceDictionary2.xaml" />
</ResourceDictionary.MergedDictionaries>
When I run the project the line with OtherAssembly throws an exception, saying that there's an error assigning the property System.Windows.ResourceDictionary.Source in that line:
But at design time, the designer shows everything in order, it finds all the resources.
I don't know, It seems that the Pack Uri syntax is not well formed.
Anybody knows why I get this error message?
I found the answer.
I needed to add a reference to OtherAssembly, as the error is not detected until run time, it's hard to detect it.

how to use wicket XsltTransformerBehavior when I have multiple .xsl files

I'm working part of a project that needs to display a .xml file with .xsl files.
Here's part of the code:
FILE_PATH = "myxsl.xsl"
...
Label content = new Label("content",xmlContent);
content.setEscapeModelStrings(false);
content.add(new XsltTransformerBehavior(FILE_PATH));
add(content);
...
Currently the page works if I use only one .xsl file. However, because the .xsl files I need to deal with can be really long, they are separated into several components.
for example, I will have
mymain.xsl, head.xsl, tables.xsl
the mymain.xsl has inclusion of the other like this
<xsl:include href="head.xsl"/>
<xsl:include href="tables.xsl"/>
I tried to set FILE_PATH to mymain.xsl, but it didn't work. The program can find mymain.xsl but cannot compile the stylesheet because it cannot find head.xsl and tables.xsl
I've been searching for a long time but still have no clue how to do this. Really appreciate any help. Thanks in advance.
I looked at the documentation of XsltTransformerBehavior, and it looks like it doesn't expose the functionality to set a custom URI resolver (which is basically what you want to do).
However, in the case that no-one else has a better solution, I can propose a workaround: Write an XSLT that merges your XSLT files into one file. See here for an XSLT that does this. If you're using Maven as build system, you can do this automatically in the generate-resources phase using the transform goal of the Maven XML Plugin. You can then associate the XsltTransformerBehavior with the single-file XSLT which will be available at run-time.

How to generate 'java code with annotations' from emf model

More precisely, I want to know, how one can model annotations into the ecore model definition. So that the generated java code would contain them. (For eg: hibernate persistence tags)
This post on the EMF Forums discusses how to use custom templates for code generation: https://www.eclipse.org/forums/index.php/t/131673/.
In a nutshell, you can dynamically provide different templates for your code generation, making it possible to insert the required annotations. In the forum post, Ed Merks (the EMF lead) suggests two pieces of information to read:
http://wiki.eclipse.org/index.php/EMF-FAQ#What_are_Dynamic_Templates.3F
http://wiki.eclipse.org/index.php/EMF-FAQ#How_do_I_use_Dynamic_Templates.3F
and a small example of how to use them:
The inserts look like this:
<%# include file="Class/getGenFeature.annotations.insert.javajetinc" fail="silent" %>
so under your templates folder you'd create files like this:
<someproject>/templates/model/Class/getGenFeature.annotations.insert.java jetinc
and whatever you put in the file will be inserted on the getter. Likely
you'd include guards like this:
<%if (isImplementation) {%>
#Something
<%}%>
Try to follow the convention of using tabs for the indentation since
these will be converted to the formatting preference of the target project.
Once you can provide your own templates you have two choices:
Add the hibernate tags by default to all your code
Modify the templates to read annotations in the ecore model.
For 2, you will need to define your own annotation source (basically a url), something like https://myproject/emf/hibernate and then add EAnnotations to your EClasses that use your custom url and provide key:value settings (e.g. the hibernate annotation to add). Your custom template can then read the annotations from the EClass, query if your source is used and then used the provided values to add the Java annotations.
The post also mentions the Teneo project, that provides JPA support for EMF. No recent development has been done (apparently), but it can be mature enough to use.
I don't think you can to this out of the box. However, you could look into the parameters of the ".genmodel" file to see if you can tweak how annotations (EAnnotations) are being output to the files. The problem with code generation templates is that they are fixed, but maybe through some option in the genmodel you can control how annotations get written to files.