{"id":96,"date":"2008-02-29T00:05:02","date_gmt":"2008-02-28T22:05:02","guid":{"rendered":"http:\/\/www.ticklishtechs.net\/2008\/02\/29\/connectors-between-compartment-shape-entries-with-dsl-tools-part-2\/"},"modified":"2020-08-13T20:46:56","modified_gmt":"2020-08-13T18:46:56","slug":"connectors-between-compartment-shape-entries-with-dsl-tools-part-2","status":"publish","type":"post","link":"https:\/\/www.ticklishtechs.net\/2008\/02\/29\/connectors-between-compartment-shape-entries-with-dsl-tools-part-2\/","title":{"rendered":"Connectors between compartment shape entries with DSL Tools – part 2"},"content":{"rendered":"
[Update (2008-05-21): <\/strong>This code is now hosted at CodePlex as part of JaDAL<\/a>. And a follow-up article<\/a> was published.]<\/p>\n This article is part of a series. A table of contents can be found at the end of the first article<\/a>. In that article you can also find a brief overview.<\/p>\n If you read this article to this point you will properly use or at least evaluate the CompartmentMapping library. I will provide you with a step-by-step tutorial. There are pretty some steps, but its the shortest way I could imagine to create my solution. Please give it a try. \ud83d\ude42<\/p>\n (If you place the xsd file in the same directory you get IntelliSense and error checking for free.)<\/p>\n<\/li>\n (Be sure you use the right xml file name here.)<\/p>\n Now press the Transform All Templates<\/em> Button in the Solution Explorer <\/em>to generate the the code from this template.<\/p>\n<\/li>\n At the top you will find commented code. Copy this code to a new cs file and remove the comments. All code you will write for the compartment mappings you will write in this file.<\/p>\n<\/li>\n Always care for (If you have already some custom rules, you can use an overloaded version of the In the <\/a><\/a><\/p>\n<\/li>\n<\/ol>\n That’s all. Only 13 steps, a few settings and conventions and 10 lines of C# code to write. I know it is not very easy but I think it is ok. And the best: as you will see it is working.<\/p>\n Now compile and start you solution. You can now create connectors from one entry of the Take a look at the properties in the Properties window<\/em> when selecting a connector. You see the guids of the corresponding entries and can use them in your code when working with this connections for code generation or whatever you need to do.<\/p>\n There are some more options besides the basics described above to configure and extend the compartment mappings.<\/p>\n Some of them can easily turned on in the xml file:<\/p>\n If you set With the You can add even more code to the C# file from step 9 to 11. There are two more methods you can override: This code is now part of the JaDAL – Just another DSL-Tools Addon Library<\/a> project. Please download the current version from that page. The download over at CodePlex<\/a> contains the source code described here, an example DSL language and the library as a binary. Future enhancements of the code will be published there, too.<\/p>\n CompartmentMapping.zip<\/a><\/p>\n<\/div>\n Part 3<\/a> and part 4<\/a> of this series will give an in depth view into the internals of the library.<\/p>\n","protected":false},"excerpt":{"rendered":" [Update (2008-05-21): This code is now hosted at CodePlex as part of JaDAL. And a follow-up article was published.] Previously on… This article is part of a series. A table of contents can be found at the end of the first article. In that article you can also find a brief overview. User guide If […]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[18,33,50,31,25,32],"_links":{"self":[{"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/posts\/96"}],"collection":[{"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/comments?post=96"}],"version-history":[{"count":2,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/posts\/96\/revisions"}],"predecessor-version":[{"id":471,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/posts\/96\/revisions\/471"}],"wp:attachment":[{"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/media?parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/categories?post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ticklishtechs.net\/wp-json\/wp\/v2\/tags?post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Previously on…<\/h3>\n
<\/ul>\n
User guide<\/h3>\n
\n
Parent1<\/code>,
Entry1<\/code>,
Parent2<\/code> and
Entry2<\/code>.
The entries need a unique identifier. You could use a name property for this, but there will be some difficulties if the user creates two entries in one shape with the same name, so I will use a guid. (Don’t forget to create a new guid in the constructor or another proper place.) <\/li>\nParent1<\/code> to
Parent2<\/code>. This will be automatically named
Parent1ReferencesParent2<\/code>. We will use this reference to present the relationship from one entry to the other. I would like to create Reference Relationships<\/em> from this relationship to the entries, but relationships of relationships are not supported. We have to store the guids of the entries in the relationship and add two Domain Properties<\/em> for this purpose to it. I named them
fromEntry<\/code> and
toEntry<\/code>.
<\/a> <\/li>\n
Allows Duplicates<\/code> property of the
Parent1ReferencesParent2<\/code> relationship to
true<\/code>. <\/li>\n
Is Custom<\/code> property of the Connection Builder<\/em> (
Parent1ReferencesParent2Builder<\/code>) in the DSL Explorer<\/em> to
true<\/code>. <\/li>\n
CompartmentMapping.dll<\/code> to both the
Dsl<\/code> and
DslPackage<\/code> project. <\/li>\n
CompartmentMappings.xml<\/code>) to your solution and write the following code in it:\n
<?<\/span>xml <\/span>version<\/span>=<\/span>"1.0<\/span>" encoding<\/span>=<\/span>"utf-8<\/span>" ?>\r\n<<\/span>CompartmentConnections\r\n <\/span>xmlns:xsi<\/span>=<\/span>"http:\/\/www.w3.org\/2001\/XMLSchema-instance<\/span>"\r\n xsi:noNamespaceSchemaLocation<\/span>=<\/span>"CompartmentMappings.xsd<\/span>"\r\n namespace<\/span>=<\/span>"BenjaminSchroeter.CompartmentMappingExample<\/span>" >\r\n <<\/span>CompartmentConnection<\/span>>\r\n <<\/span>CompartmentSource<\/span>>\r\n <<\/span>DomainClass <\/span>name<\/span>=<\/span>"Parent1<\/span>"\/>\r\n <<\/span>EntryDomainClass <\/span>name<\/span>=<\/span>"Entry1<\/span>"\/>\r\n <<\/span>Shape <\/span>name<\/span>=<\/span>"CompartmentShape1<\/span>" \/>\r\n <\/<\/span>CompartmentSource<\/span>>\r\n <<\/span>CompartmentTarget<\/span>>\r\n <<\/span>DomainClass <\/span>name<\/span>=<\/span>"Parent2<\/span>" \/>\r\n <<\/span>EntryDomainClass <\/span>name<\/span>=<\/span>"Entry2<\/span>" \/>\r\n <<\/span>Shape <\/span>name<\/span>=<\/span>"CompartmentShape2<\/span>" \/>\r\n <\/<\/span>CompartmentTarget<\/span>>\r\n <<\/span>Connection <\/span>name<\/span>=<\/span>"Parent1ReferencesParent2<\/span>">\r\n <<\/span>Shape <\/span>name<\/span>=<\/span>"Connector<\/span>" \/>\r\n <\/<\/span>Connection<\/span>>\r\n <\/<\/span>CompartmentConnection<\/span>>\r\n<\/<\/span>CompartmentConnections<\/span>><\/span><\/pre>\n
CompartmentConnections.tt<\/code> file in the same directory and right-click on the xml file and choose Generate xGen Template<\/em>. A
CompartmentMappings_xGen.tt<\/code> file will be created below the xml file and there you have to add the following lines:\n
<#@<\/span> ParentFileInjector processor=<\/span>"TTxGenDirectiveProcessor<\/span>" \r\n requires=<\/span>"fileName='CompartmentMappings.xml'<\/span>" #>\r\n<#@<\/span> <\/span>include <\/span>file=<\/span>"CompartmentConnections.tt<\/span>" #><\/span><\/pre>\n
CompartmentConnections_xGen.cs<\/code>.\n
CreateElementLink()<\/code> method in this file. Here you have to add code to store the selected compartment entries for source and target in the properties of the relationship (see 3).\n
protected override <\/span>ElementLink <\/span>CreateElementLink(Parent1 <\/span>source,\r\n SelectedCompartmentPartType <\/span>sourcePartType,\r\n Entry1 <\/span>sourceEntry,\r\n Parent2 <\/span>target,\r\n SelectedCompartmentPartType <\/span>targetPartType,\r\n Entry2 <\/span>targetEntry)\r\n{\r\n Parent1ReferencesParent2 <\/span>result = \r\n new <\/span>Parent1ReferencesParent2<\/span>(source, target);\r\n result.fromEntry = sourceEntry.Guid;\r\n result.toEntry = targetEntry.Guid;<\/strong>\r\n return <\/span>result;\r\n}<\/pre>\n<\/li>\n
CreateElementLink()<\/code> method you have stored the source and target entry information somewhere; my library does not know about this location. So we need two more methods to compare an entry with a relationship and answer the question "Is this entry the source of a given relationship?" and the same for the target. These code resists in the same file:\n
public override bool <\/span>IsEntryConnectionSource\r\n (Entry1 <\/span>entry, Parent1ReferencesParent2 <\/span>connection)\r\n{\r\n if <\/span>(entry == null<\/span>)\r\n return false<\/span>;\r\n return <\/span>connection.fromEntry.Equals(entry.Guid);<\/strong>\r\n}\r\npublic override bool <\/span>IsEntryConnectionTarget\r\n (Entry2 <\/span>entry, Parent1ReferencesParent2 <\/span>connection)\r\n{\r\n if <\/span>(entry == null<\/span>)\r\n return false<\/span>;\r\n return <\/span>connection.toEntry.Equals(entry.Guid);<\/strong>\r\n}
<\/pre>\nentry == null<\/code> this will be used to check whether the head of the shape is meant. Even if you do not allow the head as source or target this method will be called with a
null<\/code> parameter from time to time.<\/p>\n<\/li>\n
partial class<\/code> for your Domain Model <\/em>(
CompartmentMappingExampleDomainModel<\/code>) and add the following methods.\n
protected override <\/span>Type<\/span>[] GetCustomDomainModelTypes()\r\n{\r\n return <\/span>CompartmentMappingUtil<\/span>.AllCompartmentMappingRules(this<\/span>);\r\n}<\/pre>\n
AllCompartmentMappingRules()<\/code> method.)<\/p>\n<\/li>\n
DslPackage<\/code> project create a
partial class<\/code> for the generated Command Set<\/em> and add the following code:<\/p>\n
protected override <\/span>IList<\/span><MenuCommand<\/span>> GetMenuCommands()\r\n{\r\n return <\/span>CompartmentMappingUtil<\/span>.RemoveRerouteCommand\r\n (base<\/span>.GetMenuCommands());\r\n}<\/pre>\n
Parent1<\/code> shape to an entry of the
Parent2<\/code> shape. Great – isn’t it?<\/p>\n
<\/p>\n
Advanced options<\/h3>\n
\n
CompartmentSource<\/code> and
CompartmentTarget<\/code> you can specify an attribute called
allowHeadAsSource<\/code> (and
allowHeadAsTarget<\/code> respectively) and set it to
true<\/code>, to allow the head of the compartment shape as source or target. Remember, if you do this the
CreateElementLink()<\/code> method will be called with
null<\/code> values for the entries and you have to handle this. <\/li>\n
Connection<\/code> element there are two more optional attributes, too.\n
allowSelfReference<\/code> to
true<\/code> the user can create connections from one entry of one shape to another (or the same) entry of the same shape (source = target). This makes only sense if you specify
CompartmentSource<\/code> and
CompartmentTarget<\/code> to be the same Domain Class <\/em>and the same shape.<\/p>\n
suppressEntryDeletePropagation<\/code> attribute set to
true<\/code> you suppress the deletion of the connection when a corresponding compartment entry is deleted. Be careful with this setting: Wrong connections will remain in your model and produce ugly diagrams.<\/p>\n<\/li>\n
CompartmentSource<\/code> with
Source<\/code> or
CompartmentTarget<\/code> with
Target<\/code>. For these elements you don’t need to define a
EntryDomainClass<\/code> element since regular shapes do not have entries. <\/li>\n<\/ul>\n
CanAcceptAsCompartmentSource()<\/code> and
CanAcceptAsCompartmentSourceAndTarget()<\/code>. If you do so, the DSL editor will ask your code while the user moves the mouse over shapes when creating the connection to identify the current shape and entry as a valid source or target in you scenario. It is pretty much the same pattern as used in the DSL Tools itself. But remember, this method will be called very often und should have a very short running time.<\/p>\n
Update<\/h3>\n
Upcoming articles<\/h3>\n