<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dev.simantics.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Marko+Luukkainen</id>
	<title>Developer Documents - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://dev.simantics.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Marko+Luukkainen"/>
	<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php/Special:Contributions/Marko_Luukkainen"/>
	<updated>2026-04-05T19:42:52Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3469</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3469"/>
		<updated>2019-01-22T16:40:25Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.37.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|January 22th, 2019&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.37.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.37.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/groups/simantics/-/milestones/4 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.36.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/groups/simantics/-/milestones/3 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.35.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/groups/simantics/-/milestones/1 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|September 11th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.2 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.2 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.34.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|July 3rd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.1 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.1 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/groups/simantics/-/milestones/2 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3468</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3468"/>
		<updated>2019-01-22T16:23:07Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.37.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|January 22th, 2019&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.37.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.37.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.37.0 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.36.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.35.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.35.0 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|September 11th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.2 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.2 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.34.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|July 3rd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.1 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.1 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.0 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3467</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3467"/>
		<updated>2019-01-22T15:01:55Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.36.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.35.0 issues]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.35.0 Milestone]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|September 11th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.2 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.2 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.34.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|July 3rd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.1 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.1 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 commits] [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=all&amp;amp;label_name%5B%5D=1.34.0 issues]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3466</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3466"/>
		<updated>2019-01-22T14:47:01Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 1.36.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 1.35.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.35.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|September 11th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.2 1.34.2]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.34.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|July 3rd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.1 1.34.1]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 1.34.0]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3465</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3465"/>
		<updated>2019-01-22T14:42:22Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 1.36.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 1.35.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.35.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 1.34.0]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3464</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3464"/>
		<updated>2019-01-22T14:40:43Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 1.36.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.35.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 2nd, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.35.0 1.35.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.35.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.34.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|June 6th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.34.0 1.34.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.34.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3463</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3463"/>
		<updated>2019-01-22T14:28:26Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 1.36.0]&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/issues?scope=all&amp;amp;utf8=%E2%9C%93&amp;amp;state=opened&amp;amp;milestone_title=1.36.0 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3462</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Roadmap&amp;diff=3462"/>
		<updated>2019-01-22T14:27:20Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;2&amp;quot; width=&amp;quot;100%&amp;quot; &amp;quot;style=&amp;quot;background:transparent; text-align:left;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;background-color: #eeeeee;&amp;quot;&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Release&lt;br /&gt;
! align=&amp;quot;right&amp;quot;|Release date&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Project Management System&lt;br /&gt;
! align=&amp;quot;left&amp;quot;|Documentation&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.36.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|November 15th, 2018&lt;br /&gt;
| [https://gitlab.simantics.org/simantics/platform/commits/release/1.36.0 1.36.0]&lt;br /&gt;
| &lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.33.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|February 28th, 2018&lt;br /&gt;
| [[redmine:rb/release/58|1.33.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1330 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.32.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|December 27th, 2017&lt;br /&gt;
| [[redmine:rb/release/57|1.32.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1320 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.31.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|October 25th, 2017&lt;br /&gt;
| [[redmine:rb/release/56|1.31.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1310 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.30.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|August 30th, 2017&lt;br /&gt;
| [[redmine:rb/release/55|1.30.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1300 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.29.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 28th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;July 10th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/54|1.29.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1290 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.28.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 17th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;April 26th, 2017&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;June 12th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/53|1.28.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1280 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.27.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;February 22th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/52|1.27.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1270 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.26.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;October 14th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 27th, 2017&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/43|1.26.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1260 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.25.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 12th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;December 18th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/39|1.25.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1250 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.24.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;May 27th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 24th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/38|1.24.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1240 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.23.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 16th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;March 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/32|1.23.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1230 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.22.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;November 7th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;January 30th, 2016&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;May 2nd, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/31|1.22.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1220 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.21.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;September 5th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 30th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 8th, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/30|1.21.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1210 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.20.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 22th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;strike&amp;gt;December 4th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;January 1st, 2016&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/29|1.20.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1200 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 18th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/36|1.18.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1184 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.19.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;April 26th, 2015&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;November 6th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/25|1.19.0]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1190 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 10th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/35|1.18.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1183 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.18.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;July 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/33|1.18.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1182 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.18.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 20th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/17|1.18.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1181 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.5&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;January 14th, 2015&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/23|1.13.5]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1135 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.17.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 4rd, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/16|1.17.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1171 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 31st, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/22|1.13.4]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1134 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.3&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/18|1.13.3]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1133 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.16.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;September 30th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/15|1.16.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1161 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.15.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;June 26th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/14|1.15.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1151 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.13.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;May 9th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/13|1.13.2]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1132 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.13.1&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 5th, 2014&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/11|1.13.1]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_1131 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.12&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;November 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/10|1.12]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_112 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.11&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;October 18th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/9|1.11]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_111 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.10&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;April 12th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/8|1.10]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_110 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.9&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;March 14th, 2013&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/7|1.9]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_19 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.8&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;20th, December 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/6|1.8]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_18 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.7 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;b&amp;gt;1st, October 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/5|1.7]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_17 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.6&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;December 30th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;January 31st, 2012&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;TBD, Q1/2012&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;7th, June 2012&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:rb/release/4|1.6]]&lt;br /&gt;
| [https://www.simantics.org/redmine/projects/simantics-platform/wiki/Simantics_16 Change log]&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.5 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;August 31st, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 3rd, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 10th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;October 17th, 2011&amp;lt;/strike&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;b&amp;gt;October 27th, 2011&amp;lt;/b&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/121|1.5]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.4&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|May 13th, 2011&lt;br /&gt;
| [[redmine:versions/show/37|1.4]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.3 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|April 15th, 2011&amp;lt;br&amp;gt;&lt;br /&gt;
| [[redmine:versions/show/36|1.3]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.2&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;Sebtember 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to October 11th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Simantics SVN (for registered users)&lt;br /&gt;
| [[redmine:versions/show/35|1.2]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #cce3f3;&amp;quot;&lt;br /&gt;
| 1.1 (Internal only!)&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;June 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 2nd, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to July 30th, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to August 19th, 2010&lt;br /&gt;
| [[redmine:versions/show/34|1.1]]&lt;br /&gt;
| -&lt;br /&gt;
|- style=&amp;quot;background-color: #f7f7f7;&amp;quot;&lt;br /&gt;
| 1.0&lt;br /&gt;
| align=&amp;quot;right&amp;quot;|&amp;lt;strike&amp;gt;February 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;&amp;lt;strike&amp;gt;Postponed to March 1st, 2010&amp;lt;/strike&amp;gt;&amp;lt;br&amp;gt;Postponed to March 17th, 2010&lt;br /&gt;
|&lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Introduction]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Migration_To_Git&amp;diff=3332</id>
		<title>Migration To Git</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Migration_To_Git&amp;diff=3332"/>
		<updated>2017-04-11T09:42:04Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Gerrit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Recommended Reading ==&lt;br /&gt;
&lt;br /&gt;
* Official Gerrit introduction: https://gerrit-review.googlesource.com/Documentation/intro-quick.html.&lt;br /&gt;
* Gerrit tutorial: http://www.vogella.com/tutorials/Gerrit/article.html&lt;br /&gt;
&lt;br /&gt;
== Instructions for Simantics Developers ==&lt;br /&gt;
&lt;br /&gt;
=== Gerrit ===&lt;br /&gt;
&lt;br /&gt;
# Request a Gerrit account. If you already have a SVN account, it should work also in Gerrit.&lt;br /&gt;
# Generate SSH Public/Private key. If you already have one available, skip this step&lt;br /&gt;
#* Windows&lt;br /&gt;
#** Install PuTTY (msi) or download only PuTTYgen (exe) (http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)&lt;br /&gt;
#** Run PuTTYgen and generate a key&lt;br /&gt;
#*** For Type of key to generate, select &#039;&#039;&#039;SSH-2 RSA&#039;&#039;&#039;&lt;br /&gt;
#*** Press &#039;&#039;&#039;Generate&#039;&#039;&#039; button&lt;br /&gt;
#*** Move your mouse over the window until the progress bar is finished&lt;br /&gt;
#*** Write a &#039;&#039;&#039;Key passphrase&#039;&#039;&#039; to protect your private key in case your local machine is compromised. &lt;br /&gt;
#*** Save the generated public and private keys in &amp;lt;code&amp;gt;C:\Users\{username}\.ssh&amp;lt;/code&amp;gt; as follows:&lt;br /&gt;
#**** Start cmd.exe and create the target directory using &amp;lt;code&amp;gt;mkdir .ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
#**** Save private key using &#039;&#039;&#039;Conversions -&amp;gt; Export OpenSSH Key&#039;&#039;&#039;. The name &amp;lt;code&amp;gt;id_rsa&amp;lt;/code&amp;gt; is preferred because it will work out of the box with all tools.&lt;br /&gt;
#**** At the top of the window, there is a text field labeled &#039;&#039;&#039;Public key for pasting into OpenSSH authorized_keys&#039;&#039;&#039;. Copy the public key from there and save it into a text file at &amp;lt;code&amp;gt;C:\Users\{username}\.ssh\id_rsa.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
#* Linux&lt;br /&gt;
#** Generate public and private keys using &amp;lt;code&amp;gt;ssh-keygen -t rsa&amp;lt;/code&amp;gt;&lt;br /&gt;
# Go to https://www.simantics.org:8088/r/ and log in with your Gerrit username/password&lt;br /&gt;
# Select your name in the top-right corner and press &#039;&#039;Settings&#039;&#039;&lt;br /&gt;
# Go to section &#039;&#039;&#039;SSH Public Keys&#039;&#039;&#039;&lt;br /&gt;
# Open the file containing the generated public key in a text editor and copy-paste its contents to the box in Gerrit and and press &#039;&#039;&#039;Add&#039;&#039;&#039;&lt;br /&gt;
# Add and verify your contact information (name + e-mail). This will allow administrators to add you to the necessary groups to get commit access:&lt;br /&gt;
#* Go to section &#039;&#039;&#039;Contact Information&#039;&#039;&#039; and enter your &#039;&#039;&#039;Full Name&#039;&#039;&#039; there&lt;br /&gt;
#* Add a &#039;&#039;&#039;Preferred Email&#039;&#039;&#039; address using the button &#039;&#039;&#039;Register New Email&#039;&#039;&#039;&lt;br /&gt;
#* Wait for the authorization mail to arrive. It will look something like the following and contain a longish link that tends to end with == characters. Note that outlook tends to leave the trailing == characters out of the link it generates automatically. That&#039;s why it is recommended to copy the full URL from the mail into your browser to verify your e-mail address.&lt;br /&gt;
&amp;lt;pre&amp;gt;Subject:  [Gerrit Code Review] Email Verification&lt;br /&gt;
&lt;br /&gt;
Welcome to Gerrit Code Review at www.simantics.org.&lt;br /&gt;
&lt;br /&gt;
To add a verified email address to your user account, please&lt;br /&gt;
click on the following link while signed in as .....:&lt;br /&gt;
&lt;br /&gt;
http://www.simantics.org:8088/r/#/../...............................................................................==&lt;br /&gt;
&lt;br /&gt;
If you have received this mail in error, you do not need to take any&lt;br /&gt;
action to cancel the account.  The address will not be activated, and&lt;br /&gt;
you will not receive any further emails.&lt;br /&gt;
&lt;br /&gt;
If clicking the link above does not work, copy and paste the URL in a&lt;br /&gt;
new browser window instead.&lt;br /&gt;
&lt;br /&gt;
This is a send-only email address.  Replies to this message will not&lt;br /&gt;
be read or answered.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol start=&amp;quot;8&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, ask [[User:Tuukka Lehtonen]] to add you to the necessary groups and wait for this to happen.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Eclipse ===&lt;br /&gt;
&lt;br /&gt;
The following instructions are written for Eclipse Neon. There might be some differences if you are using Mars.&lt;br /&gt;
&lt;br /&gt;
# Go to preferences (General / Network Connections / SSH2) and ensure that &#039;&#039;&#039;SSH2 home&#039;&#039;&#039; points to the directory where you saved the private key.&lt;br /&gt;
# Go to preferences (Team / Git / Configuration) and ensure that the tab &#039;&#039;&#039;User Settings&#039;&#039;&#039; has the following two setting: &amp;lt;code&amp;gt;user.name&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;user.email&amp;lt;/code&amp;gt;. The specified name and email must match the values you&#039;ve put in Gerrit to be able to push changes.&amp;lt;br/&amp;gt;[[image:git-global-config.png|400px]]&lt;br /&gt;
#* Also, git has a setting called &amp;lt;code&amp;gt;core.autocrlf&amp;lt;/code&amp;gt; which is used for controlling the way git enforces line feeds to be encoded in a certain way in commits. Read [https://git-scm.com/book/tr/v2/Customizing-Git-Git-Configuration#idp31554304 the documentation] and [http://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/#the-old-system also this] to learn more. We recommend to set it to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; in Windows in order to avoid committing CRLFs to repository.&lt;br /&gt;
#* If you have a git command line client installed you can use the command &amp;lt;code&amp;gt;git config --list --show-origin&amp;lt;/code&amp;gt; to see your current global settings and find out exactly where your settings are coming from.&lt;br /&gt;
# Open &#039;&#039;Git&#039;&#039; perspective&lt;br /&gt;
# Press button &#039;&#039;&#039;Clone a Git Repository and add the clone to this view&#039;&#039;&#039; (third button in the toolbar of Git view)&lt;br /&gt;
# Select &#039;&#039;&#039;Clone URI&#039;&#039;&#039; (Don&#039;t select Gerrit, it doesn&#039;t work very well at the moment)&lt;br /&gt;
# Go back to Gerrit. Press &#039;&#039;&#039;Projects&#039;&#039;&#039; in the top-left menu and &#039;&#039;&#039;List&#039;&#039;&#039; in the submenu.&lt;br /&gt;
# Find a row named &#039;&#039;&#039;simantics/platform&#039;&#039;&#039; and press &#039;&#039;&#039;(gitweb)&#039;&#039;&#039; link at the last column.&lt;br /&gt;
# Copy the URI starting with &#039;&#039;ssh:&#039;&#039; (ssh://{username}@www.simantics.org:29418/simantics/platform.git) and paste it to &#039;&#039;&#039;URI&#039;&#039;&#039; field in &#039;&#039;&#039;Clone Git Repository dialog&#039;&#039;&#039;.&lt;br /&gt;
# This should automatically fill the other fields.&lt;br /&gt;
# Press Next. If your private key has a passphrase, Eclipse now asks it.&lt;br /&gt;
# Select all branches to be cloned (default) and press Next.&lt;br /&gt;
# Give a local directory where the repository is cloned to and press Finish.&lt;br /&gt;
# After the cloning is finished, select the &#039;&#039;&#039;platform&#039;&#039;&#039; repository in the Git Repositories view and select &#039;&#039;&#039;Import Projects...&#039;&#039;&#039; from context menu.&lt;br /&gt;
# Press Next, select all projects but &#039;&#039;&#039;org.simantics.root&#039;&#039;&#039; and press Finish.&lt;br /&gt;
# Expand the tree view of &#039;&#039;&#039;platform&#039;&#039;&#039;, expand &#039;&#039;&#039;Branches&#039;&#039;&#039; under it and &#039;&#039;&#039;Local&#039;&#039;&#039; under it. Open context menu on &#039;&#039;&#039;master&#039;&#039;&#039; branch and select &#039;&#039;&#039;Configure Branch...&#039;&#039;&#039;. Select &#039;&#039;&#039;Rebase&#039;&#039;&#039; checkbox and press &#039;&#039;&#039;Ok&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The repository you cloned contains the target platform definition that needs to be set in order for the imported Simantics codebase to compile. You can find the required target platform definition file from &#039;&#039;&#039;org.simantics.sdk.build.targetdefinition/org.simantics.sdk.build.targetdefinition.target&#039;&#039;&#039;. Open it in the target definition editor and set it as the active target platform by pressing the link &#039;&#039;&#039;Set as Target Platform&#039;&#039;&#039; at the top right corner of the editor.&lt;br /&gt;
&lt;br /&gt;
Congratulations, you&#039;ve now set up your workspace for developing the Simantics codebase in Eclipse!&lt;br /&gt;
&lt;br /&gt;
=== Updating your local repository and working space ===&lt;br /&gt;
&lt;br /&gt;
# Open context menu on &#039;&#039;&#039;platform&#039;&#039;&#039; in the Git perspective and select &#039;&#039;&#039;Pull&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Committing your changes back to shared repository ===&lt;br /&gt;
&lt;br /&gt;
# Select &#039;&#039;&#039;platform&#039;&#039;&#039; in the Git perspective and open &#039;&#039;&#039;Git Staging&#039;&#039;&#039; view.&lt;br /&gt;
# &#039;&#039;&#039;Unstaged Changes&#039;&#039;&#039; shows all files you have modified.&lt;br /&gt;
# Drag&amp;amp;drop those changes you want to commit to the box &#039;&#039;&#039;Staged Changes&#039;&#039;&#039;.&lt;br /&gt;
# Write a [[#Commit message format|commit message]]&lt;br /&gt;
# Ensure that &#039;&#039;&#039;Add Change-Id&#039;&#039;&#039; button is toggled down and the commit message contains a row starting &#039;&#039;Change-Id:&#039;&#039;.&lt;br /&gt;
#* This is required by Gerrit to be able to bind commits to specific reviews. Gerrit will replace the default zero-valued Id with a generated one when the change is pushed for review.&lt;br /&gt;
# Press &#039;&#039;&#039;Commit and Push...&#039;&#039;&#039;&lt;br /&gt;
# This opens a dialog that asks the Gerrit Branch and a Topic. Topic can be added optionally to tie multiple changes together.&lt;br /&gt;
#* Example of a topic: http://www.simantics.org:8088/r/#/q/topic:svn&lt;br /&gt;
# Go to Gerrit. In the top-left menu select &#039;&#039;&#039;My&#039;&#039;&#039; and select &#039;&#039;&#039;Changes&#039;&#039;&#039;.&lt;br /&gt;
# Your change can be seen now in the section &#039;&#039;&#039;Outgoing reviews&#039;&#039;&#039;.&lt;br /&gt;
# Click the change. This opens a review page.&lt;br /&gt;
# Ask someone to review your change. This can be done also in Gerrit by pressing &#039;&#039;&#039;Add...&#039;&#039;&#039; button in the right of the &#039;&#039;&#039;Reviewers&#039;&#039;&#039; field.&lt;br /&gt;
# If you need to make modifications to your changes based on reviews, you&#039;ll need to &#039;&#039;Amend&#039;&#039; the earlier changes to send a new patch set to Gerrit. In this case, ensure that the &#039;&#039;Amend (Edit Previous Commit)&#039;&#039; button is toggled down and you should be able to modify the earlier commit message and push the amended changes.&lt;br /&gt;
# When somebody has reviewed and accepted the change with +2, the review page will contain a &#039;&#039;&#039;Submit&#039;&#039;&#039; button that can be used to merge the change to the master branch.&lt;br /&gt;
&lt;br /&gt;
==== Commit message format ====&lt;br /&gt;
&lt;br /&gt;
In Git, the first row of the commit message is used for &#039;&#039;shortlog&#039;&#039; and generating patch file names so keep it short, concise and as descriptive as possible. The commit box in the UI shows a vertical line marking the maximum length of a commit message line and the view will inform you if you&#039;re exceeding limits. Note that the commit message box will automatically break long lines of text into separate lines to help you write a cleanly formatted commit message.&lt;br /&gt;
&lt;br /&gt;
To keep commits attached to [https://www.simantics.org/redmine/ Redmine] issues, use &amp;lt;code&amp;gt;refs #nnn&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;nnn&amp;lt;/code&amp;gt; is the issue number. This must be specified before &#039;&#039;Change-Id:&#039;&#039;. The Simantics platform Gerrit is configured to show &amp;lt;code&amp;gt;refs #nnn&amp;lt;/code&amp;gt; lines as hyperlinks to platform Redmine issues, i.e. to URL &amp;lt;code&amp;gt;https://www.simantics.org/redmine/issues/nnn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Often platform commits are also related to some issue or issues from other projects built on top of the platform. In order to retain some information about this association in the commit messages we recommend using separate rows in commit messages in form&amp;lt;code&amp;gt;[PRIVATE-mmm]&amp;lt;/code&amp;gt; where &amp;lt;code&amp;gt;mmm&amp;lt;/code&amp;gt; is the issue number in the other project.&lt;br /&gt;
&lt;br /&gt;
Gerrit reviews require a row starting &#039;&#039;Change-Id:&#039;&#039; as the last row of the commit message (excluding Signed-off-by rows). This allows Gerrit to bind commits to specific reviews. Gerrit will replace the default zero-valued Id with a generated one when the change is pushed for review.&lt;br /&gt;
&lt;br /&gt;
All in all, a typical commit message should look like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Short description of my change in under 65 characters&lt;br /&gt;
 &lt;br /&gt;
A longer description of my changes&lt;br /&gt;
that can span multiple lines.&lt;br /&gt;
 &lt;br /&gt;
refs #nnn&lt;br /&gt;
[PRIVATE-mmm] (optional, use this if the commit relates to another project)&lt;br /&gt;
&lt;br /&gt;
Change-Id: I0000000000000000000000000000000000000000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simantics Member Read-only Git Access ==&lt;br /&gt;
&lt;br /&gt;
# Register to member wiki at https://www.simantics.org/members/index.php&lt;br /&gt;
# Log into [https://www.simantics.org:8088/r/# Gerrit] using the credentials found at https://www.simantics.org/members/index.php/Code_Repository_Access&lt;br /&gt;
# Clone https://member@www.simantics.org:8088/r/p/simantics/platform.git using the HTTP password found at https://www.simantics.org:8088/r/#/settings/http-password&lt;br /&gt;
&lt;br /&gt;
The [[#Eclipse|instructions for using Eclipse]] with this git repository apply also for the generic member account. Just remember to replace the cloned SSH repository address with the HTTP address shown above.&lt;br /&gt;
&lt;br /&gt;
== Testing Reviewed Changes ==&lt;br /&gt;
&lt;br /&gt;
To test reviewed code changes locally, first you must have an Eclipse IDE setup according to the instructions in [[#Instructions for Simantics Developers]] or [[#Simantics Member Read-only Git Access]].&lt;br /&gt;
&lt;br /&gt;
Now, let&#039;s say for example we wish to grab a patch set from a review, such as review #72 (http://www.simantics.org:8088/r/72).&lt;br /&gt;
&lt;br /&gt;
# Open &#039;&#039;&#039;Git&#039;&#039;&#039; perspective&lt;br /&gt;
# Select root node of the cloned simantics-platform repository from the &#039;&#039;&#039;Git Repositories&#039;&#039;&#039; view&lt;br /&gt;
# From the context menu of the repository, select &#039;&#039;&#039;Fetch from Gerrit...&#039;&#039;&#039;&lt;br /&gt;
# In the &#039;&#039;&#039;Change&#039;&#039;&#039; field, type the change number 72 and press CTRL+SPACE to start content assist. Content assist will provide you with the selections &#039;&#039;&#039;72 - 1&#039;&#039;&#039;, and &#039;&#039;&#039;72 - 2&#039;&#039;&#039;, i.e. patch sets 1 and 2 of change 72. After selecting a patch set, the field will be filled with the value &#039;&#039;&#039;refs/changes/72/72/1&#039;&#039;&#039; or &#039;&#039;&#039;refs/changes/72/72/2&#039;&#039;&#039; depending on the patch set you selected.&lt;br /&gt;
# The default settings are otherwise recommended, i.e. &#039;&#039;&#039;Create a Local Branch&#039;&#039;&#039; and &#039;&#039;Checkout new branch&#039;&#039; to switch to the new branch immediately.&lt;br /&gt;
&lt;br /&gt;
There you have it, a local branch that has exactly the same repository state as in the code to be reviewed. Start testing!&lt;br /&gt;
&lt;br /&gt;
== Platform Git Branching Model ==&lt;br /&gt;
&lt;br /&gt;
Branch naming conventions:&lt;br /&gt;
* features: &amp;lt;code&amp;gt;feature/&amp;lt;PROJECT NAME&amp;gt;-&amp;lt;issuenumber&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Use these for developing a single feature. To keep the version history of feature branches cleaner, merge commit pushing is limited to project owners only. This means that feature branches should be used for implementing a particular thing and then merged back to master or some other branch. They should not be used as locations for eternal development and never ending try-outs.&lt;br /&gt;
* releases: &amp;lt;code&amp;gt;release/x.y.z&amp;lt;/code&amp;gt;, where x, y and z are major, minor and service version numbers respectively.&lt;br /&gt;
** Only for release stabilization branches.&lt;br /&gt;
* private work branches: &amp;lt;code&amp;gt;private/&amp;lt;PROJECT or USER NAME&amp;gt;-&amp;lt;possible descriptive suffix&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
** Should be used for personal work, trials and possibly even user or project specific custom branches that need to be kept. Gerrit is not configured enforce any rules on how these branches are used.&lt;br /&gt;
* hotfixes: &amp;lt;code&amp;gt;hotfix/x.y.z.&amp;lt;hotfix number&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Basic access rights:&lt;br /&gt;
&lt;br /&gt;
{|border=1&lt;br /&gt;
|&#039;&#039;&#039;action&#039;&#039;&#039; \ &#039;&#039;&#039;head&#039;&#039;&#039;||&#039;&#039;&#039;master&#039;&#039;&#039;&amp;lt;br/&amp;gt;&#039;&#039;&#039;release/*&#039;&#039;&#039;&amp;lt;br/&amp;gt;&#039;&#039;&#039;hotfix/*&#039;&#039;&#039;||&#039;&#039;&#039;feature/*&#039;&#039;&#039;||&#039;&#039;&#039;private/*&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;Code Review -/+2&#039;&#039;||Simantics developers||Simantics developers||Simantics developers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;Submit&#039;&#039;||Owners only||Simantics developers||Simantics developers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;Push&#039;&#039;||Owners only||Simantics developers||Simantics developers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;Push Merge Commits&#039;&#039;||Owners only||Owners Only||Simantics developers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The current plan is to loosely follow [http://nvie.com/posts/a-successful-git-branching-model/ GitFlow] rules but we&#039;ve decided to go without a separate &amp;lt;tt&amp;gt;develop&amp;lt;/tt&amp;gt; branch. This means that we treat master as a development version instead of a production version. The actual &amp;lt;tt&amp;gt;release/*&amp;lt;/tt&amp;gt; branches and tags are used to produce production versions. The rationale behind this is that we do not have a continuously evolving production version. Instead we produce new releases and products pick them up as they see fit.&lt;br /&gt;
&lt;br /&gt;
Related reading:&lt;br /&gt;
* [http://nvie.com/posts/a-successful-git-branching-model/ Git Flow branching model] by Vincent Driessen&lt;br /&gt;
* http://endoflineblog.com/gitflow-considered-harmful&lt;br /&gt;
&lt;br /&gt;
== Transferred Projects ==&lt;br /&gt;
&lt;br /&gt;
The following table lists the Git repositories that have been created so far and where their content is from in the SVN repositories.&lt;br /&gt;
&lt;br /&gt;
{|border=1&lt;br /&gt;
|&#039;&#039;&#039;SVN Location&#039;&#039;&#039;||&#039;&#039;&#039;Gerrit project&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|All over https://www.simantics.org/svn/simantics/||https://www.simantics.org:8088/r/#/admin/projects/simantics/platform&lt;br /&gt;
|-&lt;br /&gt;
|https://www.simantics.org/svn/simantics/3d||https://www.simantics.org:8088/r/#/admin/projects/simantics/3d&lt;br /&gt;
|-&lt;br /&gt;
|https://www.simantics.org/svn/simantics/fmi||https://www.simantics.org:8088/r/#/admin/projects/simantics/fmil&lt;br /&gt;
|-&lt;br /&gt;
|https://www.simantics.org/svn/simantics/r||https://www.simantics.org:8088/r/#/admin/projects/simantics/r&lt;br /&gt;
|-&lt;br /&gt;
|Everything except OpenModelica bundles from&amp;lt;br/&amp;gt;https://www.simantics.org/svn/simantics/sysdyn||https://www.simantics.org:8088/r/#/admin/projects/simantics/sysdyn&lt;br /&gt;
|-&lt;br /&gt;
|Parts of https://www.simantics.org/svn/simantics/third-party/trunk||https://www.simantics.org:8088/r/#/admin/projects/simantics/third-party&lt;br /&gt;
|-&lt;br /&gt;
|https://www.simantics.org/svn/members/fmi||https://www.simantics.org:8088/r/#/admin/projects/members/fmi&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Still Untransferred Project Locations ===&lt;br /&gt;
&lt;br /&gt;
* https://www.simantics.org/svn/simantics/interoperability&lt;br /&gt;
* https://www.simantics.org/svn/simantics/modelica&lt;br /&gt;
* https://www.simantics.org/svn/simantics/sysdyn: OpenModelica parts need to be put in a separate repository due to the huge size of OM. Preferable this repository should support LFS&lt;br /&gt;
* https://www.simantics.org/svn/simantics/tutorials&lt;br /&gt;
&lt;br /&gt;
== Q &amp;amp; A ==&lt;br /&gt;
&lt;br /&gt;
=== Will the complete SVN history be transferred to Git? ===&lt;br /&gt;
&lt;br /&gt;
Sadly, no it will not, at least for everything that is considered part of the current SVN Simantics SDK (see revisions list on page https://www.simantics.org/jenkins/job/target-simantics-head-sdk/lastStableBuild/).&lt;br /&gt;
&lt;br /&gt;
The reason for not attempting to salvage the full history into git is in the Simantics SVN repository&#039;s structure. In SVN a &amp;quot;project structure&amp;quot; is a single combination of the folders &#039;&#039;trunk&#039;&#039;, &#039;&#039;branches&#039;&#039; and &#039;&#039;tags&#039;&#039;. In git branches and tags do not exist like this as separate directories in the repository itself. The [https://git-scm.com/docs/git-svn git-svn] tool is perfectly capable of transforming a single project structure into git repository with all its history, branches and tags. At some point in the past we for decided to split the SVN repository contents into multiple project structures in the hope of modularizing the platform SDK. That hope never quite realized and what&#039;s worse, that structure has made platform release engineering much more laborous and complex than it would be with a single project structure. Now in this move to Git we decided to simplify things and just put the platform SDK projects back in a single monolithic structure of bundles, features, tests and release engineering projects. All in all, we just didn&#039;t have enough git expertise to be able to transfer all the history scattered in these multiple project structures into a single git repository and moving the current SVN project structures each into its own git repository was not an enticing option either.&lt;br /&gt;
&lt;br /&gt;
So how are we doing it right now? We have a separate migration git repository that contains a python script that simply exports all listed projects from SVN into the simantics-platform git repository structure. Our simantics-platform git repository contains a branch called &#039;svn&#039;. The SVN exporting python script was originally used to initially populate the git repository, back when we were first testing the migration. Another python script is then used to bring in changes from SVN by exporting on top of the existing simantics-platform git repository. These changes are then committed into the svn branch and merged into master from there. We are not using git svn fetch because we&#039;re just not proficient enough with git-svn to be able to use it separately for each and every project that has moved location in git already. The git master branch has already been developed onwards, but merging changes from the svn branch to it is still very easy.&lt;br /&gt;
&lt;br /&gt;
Note that the SVN repository will remain in place to keep all old versions of the platform that are still needed for maintaining existing products. We will not be moving these old branches/versions into git.&lt;br /&gt;
&lt;br /&gt;
Note that in general if you have a single SVN project structure to transfer to git it is recommended to use &amp;lt;code&amp;gt;git svn&amp;lt;/code&amp;gt; to transfer the complete history to Git.&lt;br /&gt;
&lt;br /&gt;
=== How do I convert my SVN repository into a Gerrit/git project &amp;amp; repository? ===&lt;br /&gt;
&lt;br /&gt;
The following is an example of converting a single SVN project location (&amp;lt;code&amp;gt;trunk/,branches/,tags/&amp;lt;/code&amp;gt;) into a Gerrit-hosted git repository. The instructions assume you are working on a Linux installation which has the git command line tools installed.&lt;br /&gt;
&lt;br /&gt;
SVN project structure location to be converted: https://www.simantics.org/svn/simantics/3d/&lt;br /&gt;
&lt;br /&gt;
Firstly, create a new project in Gerrit ([https://www.simantics.org:8088/r/#/admin/create-project/]). Create the project without an empty initial commit because the initial commits will come from the SVN repository anyway. In this example the project name &amp;lt;code&amp;gt;simantics/3d&amp;lt;/code&amp;gt; is used.&lt;br /&gt;
&lt;br /&gt;
Next clone the newly created git repository:&lt;br /&gt;
&amp;lt;pre&amp;gt;git clone ssh://&amp;lt;your-username&amp;gt;@www.simantics.org:29418/simantics/3d.git&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step into the cloned repository directory:&lt;br /&gt;
&amp;lt;pre&amp;gt;cd 3d&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Initialize &amp;lt;code&amp;gt;git svn&amp;lt;/code&amp;gt; with the correct SVN repository location:&lt;br /&gt;
&amp;lt;pre&amp;gt;git svn init https://www.simantics.org/svn/simantics/3d --stdlayout --prefix=svn/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Start fetching commits from the SVN repository into the empty git repository:&lt;br /&gt;
&amp;lt;pre&amp;gt;git svn fetch | tee fetch.log&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, due to the way in which &amp;lt;code&amp;gt;git svn&amp;lt;/code&amp;gt; converts branches and tags, we want to do a bit of cleanup to convert the branches into local branches before pushing them to the Gerrit&#039;s repository. Download [[Media:git-svn-convert-branches.sh|this shell script]] and execute it in the repository&#039;s root directory:&lt;br /&gt;
&amp;lt;pre&amp;gt;sh Git-svn-convert-branches.sh&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also, download [[Media:git-svn-convert-tags.sh|this shell script]] and run it to convert all the tag branches created by &amp;lt;code&amp;gt;git svn&amp;lt;/code&amp;gt; into proper git tags:&lt;br /&gt;
&amp;lt;pre&amp;gt;sh Git-svn-convert-tags.sh&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, check &amp;lt;code&amp;gt;git log --graph --oneline --all --decorate=full&amp;lt;/code&amp;gt; to see whether the conversion turned out to your liking. Also, check how large the repository became. If it turned out larger than you would expect it is probably caused by smaller or larger binary artifacts that have been committed into the SVN repository. If it turns out you want to leave certain projects outside the git svn conversion, you can use the &amp;lt;code&amp;gt;--ignore-paths&amp;lt;/code&amp;gt; argument with &amp;lt;code&amp;gt;git svn init&amp;lt;/code&amp;gt;. For example you could use &amp;lt;code&amp;gt;--ignore-paths &#039;org.simantics.openmodelica|org.simantics.om&#039;&amp;lt;/code&amp;gt; to leave out all projects starting with &amp;lt;code&amp;gt;org.simantics.openmodelica&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;org.simantics.om&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you are satisfied, push all the commits and tags to remote &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ git push --all&lt;br /&gt;
$ git push --tags&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The branch/tag conversion scripts are heavily inspired by the script available at http://timepit.eu/~frank/blog/2008/08/converting_git-svn_tags/.&lt;br /&gt;
&lt;br /&gt;
=== Why are there .keep files in Git repository folders? ===&lt;br /&gt;
&lt;br /&gt;
* https://git.wiki.kernel.org/index.php/GitFaq#Can_I_add_empty_directories.3F&lt;br /&gt;
* http://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository&lt;br /&gt;
&lt;br /&gt;
Our recommendation is to add an empty file named &#039;&#039;.keep&#039;&#039; to the empty folder to ensure it is kept in git.&lt;br /&gt;
&lt;br /&gt;
=== How can I make gerrit check X? ===&lt;br /&gt;
&lt;br /&gt;
Gerrit integrates a prolog based submit rule system that seems to be the ultimate measure for configuring how reviews work. The prolog rules can be used, among other things, to achieve the following:&lt;br /&gt;
* Example 8: Make change submittable only if Code-Review+2 is given by a non author&lt;br /&gt;
* Example 13: 1+1=2 Code-Review&lt;br /&gt;
* Example 15: Only allow Author to submit change&lt;br /&gt;
&lt;br /&gt;
See the cookbook at: https://gerrit-review.googlesource.com/Documentation/prolog-cookbook.html&lt;br /&gt;
&lt;br /&gt;
== Schedule ==&lt;br /&gt;
&lt;br /&gt;
We have set 16th December 2016 as the date when the Simantics SVN repository project locations trunks will be made read-only.&lt;br /&gt;
&lt;br /&gt;
Only those locations that have been indicated as transferred to git in [[#Transferred Projects]] have been marked read-only.&lt;br /&gt;
&lt;br /&gt;
== SVN to Git Transition TODO ==&lt;br /&gt;
&lt;br /&gt;
* Test and migrate all products trunk versions on top of the simantics-platform git master branch.&lt;br /&gt;
* &amp;lt;strike&amp;gt;Fix the SDK org.simantics.root build to produce source bundles. It should work already but it just doesn&#039;t at the moment. Perhaps something needs to defined in org.simantics.sdk.repository/pom.xml.&amp;lt;/strike&amp;gt;&lt;br /&gt;
* &amp;lt;strike&amp;gt;Set a date for when SVN trunks will be changed to read-only (16.12.2016)&amp;lt;/strike&amp;gt;&lt;br /&gt;
** &amp;lt;strike&amp;gt;E-mail simantics-developers with instructions or links to instructions about the change.&amp;lt;/strike&amp;gt;&lt;br /&gt;
* &amp;lt;strike&amp;gt;Double check all instructions:&amp;lt;/strike&amp;gt;&lt;br /&gt;
** &amp;lt;strike&amp;gt;Basic Eclipse IDE installation with Simantics graph compiler&amp;lt;/strike&amp;gt;&lt;br /&gt;
** &amp;lt;strike&amp;gt;Git instructions and platform development workflow&amp;lt;/strike&amp;gt;&lt;br /&gt;
** &amp;lt;strike&amp;gt;Gerrit instructions and practices. Only project owners shall have the right for direct push to git repositories. Others must always go through gerrit review. This is enforced via Gerrit access rights.&lt;br /&gt;
&amp;lt;/strike&amp;gt;&lt;br /&gt;
* &amp;lt;strike&amp;gt;Organize brief training and feedback session the current developers (26.10.2016)&amp;lt;/strike&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The next step is to start thinking about moving your project/product over to Gerrit!&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Quick_Development_Environment_Setup&amp;diff=3324</id>
		<title>Quick Development Environment Setup</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Quick_Development_Environment_Setup&amp;diff=3324"/>
		<updated>2017-02-20T10:46:15Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Install Java JDK and Eclipse, and Setup the IDE for Simantics Development ==&lt;br /&gt;
&lt;br /&gt;
# Get and install &#039;&#039;Java SE Development Kit 8&#039;&#039; (JDK 8). You can download the package from [http://www.oracle.com/technetwork/java/javase/downloads/index.html http://www.oracle.com/technetwork/java/javase/downloads/index.html]. Follow the installation instructions for your operating system. It is recommended to always use the latest JDK update.&lt;br /&gt;
# Get and install the latest &#039;&#039;Eclipse Classic IDE&#039;&#039; release build. You can find the package from [http://download.eclipse.org/eclipse/downloads/ http://download.eclipse.org/eclipse/downloads/]. You can select freely the installation location for the package, e.g. under your home directory. Just unzip the package to install Eclipse.&lt;br /&gt;
# After the installation of Eclipse, check that your Eclipse is set to use the right Java Runtime Environment (JRE):&lt;br /&gt;
#* In Eclipse platform, open &amp;quot;Window - Preferences&amp;quot;.&lt;br /&gt;
#* Open page “Java / Installed JREs”.&lt;br /&gt;
#* Set the JRE to point to the previously installed JDK 8.&lt;br /&gt;
# Install the Simantics Graph Compiler:&lt;br /&gt;
#* In Eclipse platform, open “Help / Install New Software...”.&lt;br /&gt;
#* Set the installation site to &amp;quot;http://www.simantics.org/update/utils&amp;quot; in the “Work with” field and press “Add...”. Give the installation site link a name when asked.&lt;br /&gt;
#* Select from the list the latest &amp;quot;Ontology development / Graph feature&amp;quot; and proceed with the installation. Restart Eclipse after the installation.&lt;br /&gt;
# Install the Subversive plug-in to the Eclipse platform:&lt;br /&gt;
#* In Eclipse platform, open &#039;&#039;“Help / Install New Software...”&#039;&#039;.&lt;br /&gt;
#* Select installation site &amp;quot;Mars - http://download.eclipse.org/releases/mars&amp;quot; to the “Work with” field from the preset list.&lt;br /&gt;
#* Click open the &amp;quot;Collaboration&amp;quot; folder and select from the list:&lt;br /&gt;
#** &#039;&#039;Subversive SVN Team Provider&#039;&#039;&lt;br /&gt;
#** &#039;&#039;Subversive SVN JDT Ignore Extensions&#039;&#039;&lt;br /&gt;
#: and proceed with the installation. Restart Eclipse after the installation.&lt;br /&gt;
# After restarting Eclipse, open the SVN Repository Exploring perspective:&lt;br /&gt;
#* In Eclipse platform, open “Window / Open Perspective / Other...”.&lt;br /&gt;
#* Select &#039;&#039;SVN Repository Exploring&#039;&#039; and press “OK”. Eclipse should open the “Install Connectors” dialog.&lt;br /&gt;
#* Select latest “SVN Kit 1.x.y” and press “Finish”, and proceed with the installation. Restart Eclipse after the installation.&lt;br /&gt;
&lt;br /&gt;
== Install Latest Simantics Target Platform ==&lt;br /&gt;
&lt;br /&gt;
# In Eclipse platform, activate the &#039;&#039;Plug-in Development&#039;&#039; perspective, either from the tab on the upper right corner of the Eclipse platform or from the “Window / Open Perspective / Other...” menu, and select &#039;&#039;Plug-in Development&#039;&#039;.&lt;br /&gt;
# Create a new general project in Eclipse by:&lt;br /&gt;
#* Selecting “File / New / Project...” menu item.&lt;br /&gt;
#* In the &amp;quot;Select a wizard&amp;quot;, select “General / Project” and press “Next”.&lt;br /&gt;
#* Give the project a name, e.g. &amp;quot;Simantics_target&amp;quot; and press &amp;quot;Finish&amp;quot;.&lt;br /&gt;
# Copy one of the following files into your system to some temporary location:&lt;br /&gt;
#* [http://www.simantics.org/download/latest/simantics.target http://www.simantics.org/download/latest/simantics.target] (for application development on Simantics platform)&lt;br /&gt;
#: The Simantics platform source code is available for [https://www.simantics.org/simantics/about-simantics/thth-simantics THTH/Simantics Division] registered members through these alternative target definitions (user name and password are asked during the installation, these are available at the [https://www.simantics.org/members/index.php/Main_Page THTH/Simantics Member Wiki]):&lt;br /&gt;
#* [http://www.simantics.org/download/latest/simantics-sdk.target http://www.simantics.org/download/latest/simantics-sdk.target] (for Simantics platform development and application development on Simantics platform)&lt;br /&gt;
# In Eclipse &#039;&#039;Package Explorer&#039;&#039; (the view on left side of the Eclipse platform):&lt;br /&gt;
#* Right-click your previously created project and select &amp;quot;Import...&amp;quot; from the context menu.&lt;br /&gt;
#* In &#039;&#039;Select wizard&#039;&#039;, select “General / File System”, and press &amp;quot;Next&amp;quot;.&lt;br /&gt;
#* Select in the “From directory” the folder where the previously downloaded file(s) are located, and select the downloaded file(s) in the file list below. Press &amp;quot;Finish&amp;quot;.&lt;br /&gt;
# Set the target platform for the development with Simantics:&lt;br /&gt;
#* In Eclipse platform, open “Window / Preferences”, and from there the “Plug-in Development / Target Platform” folder.&lt;br /&gt;
#* The new target definitions should be available in the list. Activate one of the following:&lt;br /&gt;
#** “Simantics x.y” (for application development on Simantics platform)&lt;br /&gt;
#** “Simantics SDK x.y” (for Simantics platform development and application development on Simantics platform)&lt;br /&gt;
#: and confirm the target platform definition by pressing &amp;quot;Apply&amp;quot; and/or &amp;quot;OK&amp;quot;. If you defined a &#039;&#039;Simantics SDK x.y&#039;&#039; target, you are asked for the username and the password.&lt;br /&gt;
#* Wait until Eclipse finishes downloading, this may take a while. After the download is completed, there should be several plug-ins starting with &amp;quot;org.simantics.*&amp;quot; in the Eclipse &#039;&#039;Plug-ins&#039;&#039; view (the view on the left side of Eclipse).&lt;br /&gt;
# &#039;&#039;&#039;Keep your platform up-to-date!&#039;&#039;&#039; Updating is as easy as reloading the target platform from &#039;&#039;Target Platform&#039;&#039; preference page:&lt;br /&gt;
#* In Eclipse platform, open “Window / Preferences”, and from there the “Plug-in Development / Target Platform” folder.&lt;br /&gt;
#* Select the active target platform, e.g. &#039;&#039;Simantics SDK x.y&#039;&#039;, from the list and press &amp;quot;Reload&amp;quot;.&lt;br /&gt;
#* Wait until the platform is updated.&lt;br /&gt;
&lt;br /&gt;
== Test Your Installation ==&lt;br /&gt;
&lt;br /&gt;
Test your installation with the [http://dev.simantics.org/index.php/Tutorial:_Ontology_Development Simantics movie tutorial]:&lt;br /&gt;
&lt;br /&gt;
# Download &#039;&#039;Simantics movie tutorial&#039;&#039; plug-ins into your Eclipse workspace:&lt;br /&gt;
#* Get [https://www.simantics.org/jenkins/job/Tutorials/job/package-movie-tutorial-head/lastSuccessfulBuild/artifact/movie-tutorial.zip]&lt;br /&gt;
#* In Eclipse platform, select  “File / Import...” menu item.&lt;br /&gt;
#* In the &amp;quot;Select&amp;quot; dialog, select “General / Existing Projects into Workspace” and press “Next”.&lt;br /&gt;
#* Select the “Select archive file:” radio button and press “Browse” to find the downloaded movie-tutorial.zip.&lt;br /&gt;
#* Press “Select All” and “Finish”.&lt;br /&gt;
# Run movie.product:&lt;br /&gt;
#* From the &#039;&#039;Package Explorer&#039;&#039; view, open “org.simantics.movie.ui&#039;&#039; / Movie.product”.&lt;br /&gt;
#* From the &#039;&#039;Overview&#039;&#039; page of the opened product editor, press “Launch an Eclipse application”. &lt;br /&gt;
&lt;br /&gt;
If you managed to start the &#039;&#039;movie&#039;&#039; product, your development platform should be operational.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Happy developing with Simantics!&#039;&#039;&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3212</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3212"/>
		<updated>2016-03-17T12:22:25Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Unrecognized child elements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3211</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3211"/>
		<updated>2016-03-17T12:21:48Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Ordered child */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3210</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3210"/>
		<updated>2016-03-17T12:21:25Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* ID references */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3209</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3209"/>
		<updated>2016-03-17T12:20:28Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Attribute composition */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3208</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3208"/>
		<updated>2016-03-17T12:19:37Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Indicators (choice, sequence, all) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3207</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3207"/>
		<updated>2016-03-17T12:19:18Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Element */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3206</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3206"/>
		<updated>2016-03-17T12:18:46Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* ComplexType */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3205</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3205"/>
		<updated>2016-03-17T12:18:12Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* SimpleType */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3204</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3204"/>
		<updated>2016-03-17T12:01:43Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* ID references */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: white; background-color:green;&amp;quot; &lt;br /&gt;
|Predicate&lt;br /&gt;
|Object&lt;br /&gt;
|Graph&lt;br /&gt;
|- style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Basic information&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Is Related To&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-style=&amp;quot;text-align: center; color: white; background-color:blue;&amp;quot; &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|Other statements&lt;br /&gt;
|- style=&amp;quot;color: blue; background-color:#ffffcc;&amp;quot;&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3203</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3203"/>
		<updated>2016-03-17T11:45:21Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Simantics XML-Schema Conversion version 0.1=&lt;br /&gt;
Plugins:&lt;br /&gt;
* org.simantics.xml.sax&lt;br /&gt;
* org.simantics.xml.sax.base&lt;br /&gt;
* org.simantics.xml.sax.ui&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
Simantics XML-Schema conversion creates:&lt;br /&gt;
* Simantics ontology as .pgraph file&lt;br /&gt;
* Java classes for SAX based parser&lt;br /&gt;
Schema conversion does not support:&lt;br /&gt;
* XML file export&lt;br /&gt;
* Many of the XML schema definitions&lt;br /&gt;
* Group definitions&lt;br /&gt;
* Attribute constraining facets&lt;br /&gt;
== Notes ==&lt;br /&gt;
This work was done in PDS Integration project in co-operation with VTT and Fortum. Schema conversion was used for converting Proteus 3.6.0 XML Schema to Simantics ontology. Due to limited scope of the schema, the converter supports only limited part of the XML Schema definitions.&lt;br /&gt;
=Ontology definitions based on XML schema concepts=&lt;br /&gt;
XML Schema conversion creates types and relations based on XML schema concepts that are used in the conversion&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Hard-coded ontology definition&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|hasAttribute &amp;lt;R L0.HasPropertyBase||relation for all element/attribute relations&lt;br /&gt;
|-&lt;br /&gt;
|hasID &amp;lt;R hasAttribute||Base relation for IDs (Attributes with xsd:ID type)&lt;br /&gt;
|-&lt;br /&gt;
|ComplexType &amp;lt;T L0.Entity||Base type for ComplexTypes&lt;br /&gt;
|-&lt;br /&gt;
|hasComplexType &amp;lt;R L0.IsComposedOf||Base relation for containing elements that inherit the specified ComplexType&lt;br /&gt;
|-&lt;br /&gt;
|AttributeGroup  &amp;lt;T L0.Entity||Base type for AttributeGroups&lt;br /&gt;
|-&lt;br /&gt;
|Element &amp;lt;T L0.Entity||Base type for Elements&lt;br /&gt;
|-&lt;br /&gt;
|hasElement &amp;lt;R L0.IsComposedOf||Base relation for containing elements&lt;br /&gt;
|-&lt;br /&gt;
|ElementList &amp;lt;T L0.List||Base type for Lists containing Elements (storing the order of the elements)&lt;br /&gt;
|-&lt;br /&gt;
|hasElementList &amp;lt;R L0.IsComposedOf||Base relation for element containing element lists. Used for creating Element type specific lists.&lt;br /&gt;
|-&lt;br /&gt;
|hasOriginalElementList &amp;lt;R hasElementList||Relation for element containing element lists. Stores the order of the all the child elements.&lt;br /&gt;
|-&lt;br /&gt;
|hasReference &amp;lt;R L0.IsRelatedTo||Base relation for object references (converted ID references)&lt;br /&gt;
|-&lt;br /&gt;
|hasExternalReference &amp;lt;R L0.IsWeaklyRelatedTo||Relation for references between data imported from different files. Note: external references must be created with post process functions, since schema conversion itself is not able to resolve references between different imports.&lt;br /&gt;
|}&lt;br /&gt;
= Datatypes =&lt;br /&gt;
XML uses three types of attributes, Atomic, List, and Union. Current XML Schema conversion support only Atomic attributes.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Atomic||Supported||&lt;br /&gt;
|-&lt;br /&gt;
|List||Not Supported||&lt;br /&gt;
|-&lt;br /&gt;
|Union||Not supported||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Primitive attributes are converted to Layer0 literals. List of primitive datatypes and respective literal types is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|string||L0.String||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||L0.Boolean||&lt;br /&gt;
|-&lt;br /&gt;
|decimal||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|float||L0.Float||&lt;br /&gt;
|-&lt;br /&gt;
|double||L0.Double||&lt;br /&gt;
|-&lt;br /&gt;
|duration&lt;br /&gt;
|-&lt;br /&gt;
|dateTime&lt;br /&gt;
|-&lt;br /&gt;
|time||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|date||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|gYearMonth&lt;br /&gt;
|-&lt;br /&gt;
|gYear&lt;br /&gt;
|-&lt;br /&gt;
|gMonthDay&lt;br /&gt;
|-&lt;br /&gt;
|gDay&lt;br /&gt;
|-&lt;br /&gt;
|gMonth&lt;br /&gt;
|-&lt;br /&gt;
|hexBinary	&lt;br /&gt;
|-&lt;br /&gt;
|base64Binary	&lt;br /&gt;
|-&lt;br /&gt;
|anyUri||L0.Uri&lt;br /&gt;
|-&lt;br /&gt;
|QName&lt;br /&gt;
|-&lt;br /&gt;
|NOTATION&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Other built-in datatypes are converted to Layer0 literal types as well:&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML datatype&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|normalizedString||L0.String	&lt;br /&gt;
|-&lt;br /&gt;
|token||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|language&lt;br /&gt;
|-&lt;br /&gt;
|NMTOKEN||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|-&lt;br /&gt;
|NCName&lt;br /&gt;
|-&lt;br /&gt;
|ID||L0.String||ID attributes use XML.hasID property relation.  An element is expected to have only one attribute with ID type.&lt;br /&gt;
|- &lt;br /&gt;
|IDREF||L0.String&lt;br /&gt;
|-&lt;br /&gt;
|IDREFS&lt;br /&gt;
|-&lt;br /&gt;
|ENTITY&lt;br /&gt;
|-&lt;br /&gt;
|ENTITIES&lt;br /&gt;
|-&lt;br /&gt;
|integer||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|nonPositiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|negativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|long||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|int||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|short||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|byte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|nonNegativeInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedLong||L0.Long&lt;br /&gt;
|-&lt;br /&gt;
|unsignedShort||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|unsignedByte||L0.Byte&lt;br /&gt;
|-&lt;br /&gt;
|positiveInteger||L0.Integer&lt;br /&gt;
|-&lt;br /&gt;
|yearMonthDuration&lt;br /&gt;
|-&lt;br /&gt;
|dayTimeDuration&lt;br /&gt;
|-&lt;br /&gt;
|dateTimeStamp&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
XML schema allows defining new attribute types with constraining facets. Constraining facets are not currently supported.&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!XML Constraining facets&lt;br /&gt;
!Simantics&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|length		&lt;br /&gt;
|-&lt;br /&gt;
|minLength		&lt;br /&gt;
|-&lt;br /&gt;
|maxLength&lt;br /&gt;
|-&lt;br /&gt;
|pattern&lt;br /&gt;
|-&lt;br /&gt;
|enumeration&lt;br /&gt;
|-&lt;br /&gt;
|whitespace&lt;br /&gt;
|-&lt;br /&gt;
|maxInclusive&lt;br /&gt;
|-&lt;br /&gt;
|maxExclusive&lt;br /&gt;
|-&lt;br /&gt;
|minInclusive&lt;br /&gt;
|-&lt;br /&gt;
|minExclusive&lt;br /&gt;
|-&lt;br /&gt;
|totalDigits&lt;br /&gt;
|-&lt;br /&gt;
|fractionDigits&lt;br /&gt;
|-&lt;br /&gt;
|Assertions&lt;br /&gt;
|-&lt;br /&gt;
|explicitTimeZone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In addition, individual attributes can be converted to a single array with Attribute Composition rule. Supported array datatypes are: &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Conversion configuration&lt;br /&gt;
!Simantics&lt;br /&gt;
|-&lt;br /&gt;
|doubleArray||L0.DoubleArray&lt;br /&gt;
|-&lt;br /&gt;
|stringArray||L0.StringArray	&lt;br /&gt;
|}&lt;br /&gt;
=Structures=&lt;br /&gt;
==Type definitions==&lt;br /&gt;
===SimpleType===&lt;br /&gt;
XML schema allows SimpleTypes to be used as Element types for elements without child elements or as attribute types. &lt;br /&gt;
When simpleType is used as attributes, the type will be converted to functional property relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:simpleType name=&amp;quot;LengthUnitsType&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:enumeration value=&amp;quot;mm&amp;quot;/&amp;gt;&lt;br /&gt;
    …			&lt;br /&gt;
  &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;UnitsOfMeasure&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:annotation&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:documentation&amp;gt;These are from …&amp;lt;/xsd:documentation&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:annotation&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Distance&amp;quot; type=&amp;quot;LengthUnitsType&amp;quot; default=&amp;quot;Millimetre&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasLengthUnitsType &amp;lt;R PRO.XML.hasAttribute : L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&lt;br /&gt;
PRO.hasUnitsOfMeasure &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasUnitsOfMeasureList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.UnitsOfMeasure &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.UnitsOfMeasure.hasDistance &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   &amp;lt;R PRO.hasLengthUnitsType&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When simpleType is used as definition of Element, the definition is converted to inheritance from the base literal type. In the following example, Knot elements xsd:double base is converted to inheritance to L0.Double:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Knot&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:double&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:minInclusive value=&amp;quot;0.0&amp;quot;/&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
 &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.hasKnots.Knot &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.ComplexTypes.hasKnots.KnotList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.ComplexTypes.Knots.Knot &amp;lt;T PRO.XML.Element &amp;lt;T L0.Double&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===ComplexType===&lt;br /&gt;
Schema conversion creates hard-coded ComplexType entity as a base type for ComplexTypes.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.XML.ComplexType &amp;lt;T L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ComplexTypes that are defined in the input schema are converted to L0.Entities, which inherit the hard-coded ComplexType, and are put into “ComplexTypes” library.  Conversion also generates ComplexType specific generic relation for composition, and another relation for lists. &lt;br /&gt;
Particles of a ComplexType are converted to ComplexType and particle specific relations inheriting the particle type related relation.  Also, Attributes of the ComplexType are converted to the ComplexType and Attribute specific relations.&lt;br /&gt;
For example, ComplexType “PlantItem” is converted to “ComplexTypes.PlantItem” entity, it has a “ComplexTypes.hasPlantItem” composition relation, and “ComplexTypes.hasPlantItemList” relation for lists. “ID” attribute is converted to “ComplexTypes.PlantItem.hasID” functional relation, and choice particle “Presentation” is converted to “ComplexTypes.PlantItem.hasPresentation” relation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:complexType name=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Presentation&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
    &amp;lt;xsd:element name=&amp;quot;ModelNumber&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ID&amp;quot; type=&amp;quot;xsd:ID&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;TagName&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
  &amp;lt;xsd:attribute name=&amp;quot;ComponentType&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;xsd:simpleType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:restriction base=&amp;quot;xsd:NMTOKEN&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Normal&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Explicit&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:enumeration value=&amp;quot;Parametric&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:restriction&amp;gt;&lt;br /&gt;
   &amp;lt;/xsd:simpleType&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:attribute&amp;gt;&lt;br /&gt;
  …&lt;br /&gt;
&amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.ComplexTypes.PlantItem &amp;lt;T PRO.XML.ComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItem &amp;lt;R PRO.XML.hasComplexType&lt;br /&gt;
PRO.ComplexTypes.hasPlantItemList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
   --&amp;gt; PRO.ComplexTypes.PlantItem&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasPresentation &amp;lt;R PRO.hasPresentation&lt;br /&gt;
   --&amp;gt; PRO.Presentation&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
…&lt;br /&gt;
PRO.ComplexTypes.PlantItem.hasComponentType &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Element==&lt;br /&gt;
Element definitions are processed similarly to ComplexTypes, but the converted types are put directly into the ontology without any library. Hence, Element “PlantModel” is converted to “PlantModel” entity.	&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;PlantModel&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;PlantInformation&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:element ref=&amp;quot;Extent&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:any namespace=&amp;quot;##targetNamespace&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasPlantModel &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasPlantModelList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.PlantModel &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.PlantModel.hasPlantInformation &amp;lt;R PRO.hasPlantInformation&lt;br /&gt;
   --&amp;gt; PRO.PlantInformation&lt;br /&gt;
PRO.PlantModel.hasExtent &amp;lt;R PRO.hasExtent&lt;br /&gt;
   --&amp;gt; PRO.Extent&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When Element definition is defined with ComplexContent, ComplexContent’s extension’s base is converted to L0.Inheritance relation between the types. For example “Equpiment” Element has “PlantItem” as a base extension, so “Equipment” entity is inherited from “PlantItem” entity.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Equipment&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;PlantItem&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:choice minOccurs=&amp;quot;0&amp;quot; maxOccurs=&amp;quot;unbounded&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Discipline&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;MinimumDesignPressure&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;Equipment&amp;quot;/&amp;gt;&lt;br /&gt;
          …&lt;br /&gt;
        &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;ProcessArea&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;Purpose&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasEquipment &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasEquipmentList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.Equipment &amp;lt;T PRO.XML.Element &amp;lt;T PRO.PlantItem&lt;br /&gt;
PRO.Equipment.hasProcessArea &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasPurpose &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Equipment.hasDiscipline &amp;lt;R PRO.hasDiscipline&lt;br /&gt;
   --&amp;gt; PRO.Discipline&lt;br /&gt;
PRO.Equipment.hasMinimumDesignPressure &amp;lt;R PRO.hasMinimumDesignPressure&lt;br /&gt;
   --&amp;gt; PRO.MinimumDesignPressure&lt;br /&gt;
…&lt;br /&gt;
PRO.Equipment.hasEquipment &amp;lt;R PRO.hasEquipment&lt;br /&gt;
   --&amp;gt; PRO.Equipment&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Indicators (choice, sequence, all)==&lt;br /&gt;
When Indicators have maxOccurs larger than 1, relations generated according to particles have no multiplicity restrictions (ass all previous examples are defined).  When indicator is choice with maxOccurs=1 (default value for maxOccurs), the particle relations is expected to refer to only one object that conforms to one of the specified types.&lt;br /&gt;
For example, Element “TrimmedCurve” has choice indicator with 4 elements (“Circle”, “PCircle”, “Ellipse”, “PEllipse), and that choice is converted to “TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse” relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;TrimmedCurve&amp;quot; substitutionGroup=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:complexContent&amp;gt;&lt;br /&gt;
      &amp;lt;xsd:extension base=&amp;quot;Curve&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:sequence&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:choice&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Circle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PCircle&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;Ellipse&amp;quot;/&amp;gt;&lt;br /&gt;
            &amp;lt;xsd:element ref=&amp;quot;PEllipse&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;/xsd:choice&amp;gt;&lt;br /&gt;
          &amp;lt;xsd:element ref=&amp;quot;GenericAttributes&amp;quot; minOccurs=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/xsd:sequence&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;StartAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;xsd:attribute name=&amp;quot;EndAngle&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/xsd:extension&amp;gt;&lt;br /&gt;
    &amp;lt;/xsd:complexContent&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.hasTrimmedCurve &amp;lt;R PRO.XML.hasElement&lt;br /&gt;
PRO.hasTrimmedCurveList &amp;lt;R PRO.XML.hasElementList&lt;br /&gt;
PRO.TrimmedCurve &amp;lt;T PRO.XML.Element &amp;lt;T PRO.Curve&lt;br /&gt;
PRO.TrimmedCurve.hasStartAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasEndAngle &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.Double&lt;br /&gt;
PRO.TrimmedCurve.hasCircleOrPCircleOrEllipseOrPEllipse &amp;lt;R PRO.hasCircle &amp;lt;R PRO.hasPCircle &amp;lt;R PRO.hasEllipse &amp;lt;R PRO.hasPEllipse&lt;br /&gt;
   --&amp;gt; PRO.Circle&lt;br /&gt;
   --&amp;gt; PRO.PCircle&lt;br /&gt;
   --&amp;gt; PRO.Ellipse&lt;br /&gt;
   --&amp;gt; PRO.PEllipse&lt;br /&gt;
PRO.TrimmedCurve.hasGenericAttributes &amp;lt;R PRO.hasGenericAttributes&lt;br /&gt;
   --&amp;gt; PRO.GenericAttributes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that Model Group definitions are not currently supported!&lt;br /&gt;
&lt;br /&gt;
=Customization via configuration=&lt;br /&gt;
&lt;br /&gt;
==Attribute composition==&lt;br /&gt;
&lt;br /&gt;
Attribute composition rule allows converting separate attributes into one array. For example, following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;AttributeComposition Name=&amp;quot;XYZ&amp;quot; Type = &amp;quot;doubleArray&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;X&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Y&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;Z&amp;quot; Type =&amp;quot;double&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/AttributeComposition&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
causes “X”,  “Y” and “Z”  double attributes in “Coordinate” Element definition&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Coordinate&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;X&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Y&amp;quot; type=&amp;quot;xsd:double&amp;quot; use=&amp;quot;required&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;Z&amp;quot; type=&amp;quot;xsd:double&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
to be converted to “XYZ” double array:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Coordinate &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Coordinate.hasXYZ &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.DoubleArray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==ID references==&lt;br /&gt;
&lt;br /&gt;
Referencing other XML elements is usually done using element IDs.  Using ID Provider and ID Reference rules allows converting these references to statements in Simantics DB.&lt;br /&gt;
ID Provider rule is used for retrieving the ID from referred objects.  The rule does not affect the generated ontology.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDProvider&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Attribute Name=&amp;quot;ID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDProvider&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 ID Reference rule is used for objects that use ID references. ID Source tells which attribute is used to refer another Element, and Reference defines the name of the relation. With the following rule:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;IDReference&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;Connection&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;IDSource Name=&amp;quot;ToID&amp;quot; Type =&amp;quot;string&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Name=&amp;quot;ToIDRef&amp;quot; Type =&amp;quot;ref&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/IDReference&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
“Connection” element definition’s “ToID” reference is converted to ToIDRef relation. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;xsd:element name=&amp;quot;Connection&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;xsd:complexType&amp;gt;&lt;br /&gt;
    &amp;lt;xsd:attribute name=&amp;quot;ToID&amp;quot; type=&amp;quot;xsd:string&amp;quot;/&amp;gt;&lt;br /&gt;
    …&lt;br /&gt;
  &amp;lt;/xsd:complexType&amp;gt;&lt;br /&gt;
&amp;lt;/xsd:element&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The original attribute is kept, so that if ID reference cannot be located, the information about the reference still exists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
PRO.Connection &amp;lt;T PRO.XML.Element&lt;br /&gt;
PRO.Connection.hasToID &amp;lt;R PRO.XML.hasAttribute: L0.FunctionalRelation&lt;br /&gt;
   --&amp;gt; L0.String&lt;br /&gt;
PRO.Connection.ToIDRef &amp;lt;R PRO.XML.hasReference&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In imported data, the reference statement will point to referred Element, if the parser is able to locate a Element with the given ID.&lt;br /&gt;
 &lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align: center; color: green;&amp;quot;&lt;br /&gt;
!Predicate&lt;br /&gt;
!Object&lt;br /&gt;
!Graph&lt;br /&gt;
|-&lt;br /&gt;
|Basic information&lt;br /&gt;
|-&lt;br /&gt;
|InstanceOf&lt;br /&gt;
|Connection&lt;br /&gt;
|DB&lt;br /&gt;
|-&lt;br /&gt;
|Is Related To&lt;br /&gt;
|-&lt;br /&gt;
|hasToID&lt;br /&gt;
|V_02_N6 (edit)&lt;br /&gt;
|DB&lt;br /&gt;
|-&lt;br /&gt;
|ToIDRef&lt;br /&gt;
|$412442 : (Nozzle)&lt;br /&gt;
|DB&lt;br /&gt;
|-&lt;br /&gt;
|Other statements&lt;br /&gt;
|-&lt;br /&gt;
|hasConnection/Inverse&lt;br /&gt;
|$416145 : (PipingNetworkSegment)&lt;br /&gt;
|DB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Ordered child==&lt;br /&gt;
Ordered child rule allows storing the original order of the elements into lists. The rules either force the creating of the lists (used when the schema is interpreted to be indifferent of the order), or disabling the list generation. &lt;br /&gt;
Currently the rule hat two types, original and child. An original type rule sets if all the child elements are out into “OriginalElementList”.  An child rule sets if the child elements are added to type specific lists.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;original&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;OrderedChild Type=&amp;quot;child&amp;quot; Value=&amp;quot;disable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;ComplexType Name = &amp;quot;PlantItem&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/OrderedChild&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Unrecognized child elements==&lt;br /&gt;
Unrecognized child element rule allows processing XML files that do not conform to given schema, and use different element names. In practice, the rule allows injecting Java code to generated parser classes. The code is put into method, which signature is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void configureChild(WriteGraph graph, Deque&amp;lt;Element&amp;gt; parents, Element element, Element child) throws DatabaseException&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The method is called with ”element” as the element, which conforms to given type in the rule’s configuration, and ”child” is the child element, that could not be recognized.  The following example is  used for handling incorrect files, which have replaced element name with the contents of attribute “name”. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;UnrecognizedChildElement&amp;gt;&lt;br /&gt;
  &amp;lt;Element Name =&amp;quot;GenericAttributes&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;JavaMethod&amp;gt;&lt;br /&gt;
  // Some commercial software do not handle GenericAttribute elements properly:&lt;br /&gt;
  // they use &amp;quot;Name&amp;quot; attribute&#039;s value as element&#039;s name.&lt;br /&gt;
  GenericAttribute ga = new GenericAttribute();&lt;br /&gt;
  java.util.List&amp;amp;lt;Attribute&amp;amp;gt; attributes = new java.util.ArrayList&amp;amp;lt;Attribute&amp;amp;gt;();&lt;br /&gt;
  attributes.addAll(child.getAttributes());&lt;br /&gt;
  attributes.add(new Attribute(&amp;quot;Name&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;&amp;quot;, child.getQName()));&lt;br /&gt;
  Element newChild = new Element(&amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;GenericAttribute&amp;quot;, attributes);&lt;br /&gt;
  newChild.setParser(ga);&lt;br /&gt;
  Resource res = ga.create(graph, newChild);&lt;br /&gt;
  if (res != null) {&lt;br /&gt;
    newChild.setData(res);&lt;br /&gt;
    parents.push(element);&lt;br /&gt;
    ga.configure(graph, parents, newChild);&lt;br /&gt;
    connectChild(graph, element, newChild);&lt;br /&gt;
    parents.pop();&lt;br /&gt;
  }&lt;br /&gt;
  &amp;lt;/JavaMethod&amp;gt;&lt;br /&gt;
&amp;lt;/UnrecognizedChildElement&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
An example of incorrect file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;Assembly Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Bendingradiusrtube Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm&amp;quot; ComosUnits=&amp;quot;mm M01.15&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;CostCode Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When the content should be:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;GenericAttributes Number=&amp;quot;28&amp;quot; Set=&amp;quot;Values&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Assembly&amp;quot; Format=&amp;quot;string&amp;quot; Value=&amp;quot;5. Auxiliary Steam System&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;Bendingradiusrtube&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;0&amp;quot; Units=&amp;quot;mm“ /&amp;gt;&lt;br /&gt;
  &amp;lt;GenericAttribute Name=&amp;quot;CostCode&amp;quot; Format=&amp;quot;double&amp;quot; Value=&amp;quot;607&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=References=&lt;br /&gt;
&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 1: Structures http://www.w3.org/TR/xmlschema11-1/&lt;br /&gt;
# W3C XML Schema definition language (XSD) 1.1 Part 2: Datatypes http://www.w3.org/TR/xmlschema11-2/&lt;br /&gt;
# Layer0 specification http://dev.simantics.org/images/c/c8/Layer0.pdf&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3202</id>
		<title>XML Schema Conversion</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=XML_Schema_Conversion&amp;diff=3202"/>
		<updated>2016-03-17T10:22:22Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: Created page with &amp;quot;Simantics includes a tool for convering XML schemas to Simantics ontologies.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Simantics includes a tool for convering XML schemas to Simantics ontologies.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3201</id>
		<title>Simantics Developer Documentation</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3201"/>
		<updated>2016-03-17T10:21:35Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
[[image:Simantics_logo_pile_01.png|right|border|400px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Simantics&#039;&#039;&#039; is a software platform for modelling and simulation. The system has client-server architecture with a semantic ontology-based modelling database and Eclipse framework -based client software with plug-in interface. The Simantics platform and many of its components are open source under [http://www.eclipse.org/legal/epl-v10.html Eclipse Public License (EPL)].&lt;br /&gt;
&lt;br /&gt;
The philosophy of the Simantics platform is to offer an open, high level application platform on which different computational tools can be easily integrated to form a common environment for modelling and simulation. The platform includes several modelling tools, so-called editors, for e.g. 2D graph-like hierarchical model composition and semantic graph browsing.&lt;br /&gt;
&lt;br /&gt;
One of the biggest innovations in the Simantics platform is the semantic modelling approach itself and high-level ontology tools. The semantic database, i.e. triplestore, on the server side enables high performance data management and arbitrary mappings of data. This enables e.g. efficient mapping of simulation and measurement data to the model configuration and its visualisation.&lt;br /&gt;
&lt;br /&gt;
The Simantics development and maintenance process is built to be solid and scalable from the very beginning. The objective is to aim far to the future what comes to requirements for scalability, usability, and reliability.&lt;br /&gt;
&lt;br /&gt;
This &#039;&#039;Simantics Developer Documentation&#039;&#039; is targeted to programmers and software developers developing either the platform itself or additional plug-ins to be used with or on the platform. The [[userwiki:Main_Page|Simantics End User Documentation]] complements to documentation for the Simantics platform offering overview and detailed information about the platform from the user&#039;s point of view. The [https://www.simantics.org/simantics Simantics] website is the source of information for the Simantics project and related subjects[[Tutorials|.]]&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:white;&amp;quot;&amp;gt;Disclaimer Warning: This site may cause narcolepsia in some readers. Consult your doctor if sensitive to boredom.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;75%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
* [[Glossary]]&lt;br /&gt;
* [[Introduction to Simantics Architecture]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Data View]]&lt;br /&gt;
* [[Component View]]&lt;br /&gt;
* [[Licensing|Licensing]]&lt;br /&gt;
* [[Useful Links]]&lt;br /&gt;
&amp;lt;!--* [[Simantics Specifications|Specifications]]--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Documents ===&lt;br /&gt;
&lt;br /&gt;
* [[Quick Development Environment Setup|Quick Development Environment Setup Guide]]&lt;br /&gt;
* [[Target Platform]]&lt;br /&gt;
* [[Development Practices]]&lt;br /&gt;
* [[Internalization]]&lt;br /&gt;
* [[Update Site]]&lt;br /&gt;
* [[Coding Convention]]&lt;br /&gt;
* [[Tools]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
* [[FAQ]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Ontology Development ===&lt;br /&gt;
&lt;br /&gt;
* [[:Media:Layer0.pdf|Layer0.pdf]] ([[:File:Layer0.pdf|log]])&lt;br /&gt;
* [[Graph Compiler]]&lt;br /&gt;
* [[Transferable Graph]]&lt;br /&gt;
* [[Binary Container Format]]&lt;br /&gt;
* [[Graph File Format]]&lt;br /&gt;
* [[Version Migration]]&lt;br /&gt;
* [[Tutorial: Ontology Development]]&lt;br /&gt;
* [[XML Schema Conversion]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Database Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Interface summary]]&lt;br /&gt;
* [[Tutorial: Quickstart]]&lt;br /&gt;
* [[Tutorial: Database Development]]&lt;br /&gt;
* [[Resource Adaptation]]&lt;br /&gt;
* [[Resource Serialization]]&lt;br /&gt;
* [[Inverse Relations]]&lt;br /&gt;
* [[Virtual Graphs]]&lt;br /&gt;
* [[Functions]]&lt;br /&gt;
* [[Procedural Values]]&lt;br /&gt;
* [[Variable]]&lt;br /&gt;
* [[Undo Mechanism]]&lt;br /&gt;
* [[Team Features]]&lt;br /&gt;
* [[Subgraph Extents]]&lt;br /&gt;
* [[Database Testing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Data management &amp;amp; Experiment Control ===&lt;br /&gt;
&lt;br /&gt;
* [[Databoard Specification]]&lt;br /&gt;
* [[Databoard Developer Manual|Databoard Java Manual]]&lt;br /&gt;
* [[Experiment Control]]&lt;br /&gt;
* [[Dataflows]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== UI Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Org.simantics.browsing.ui_Manual|Browser Manual]]&lt;br /&gt;
* [[org.simantics.browsing.ui.feature|Browser Component]]&lt;br /&gt;
* [[Org.simantics.scenegraph.loader|Scene Graph Loader]]&lt;br /&gt;
* [[Org.simantics.message|Messages]]&lt;br /&gt;
* [[Org.simantics.views|Modelled Views]]&lt;br /&gt;
* [[Org.simantics.document|Documents]]&lt;br /&gt;
* [[Selection View]]&lt;br /&gt;
|}&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Simantics Constraint Language===&lt;br /&gt;
&lt;br /&gt;
* [http://www.simantics.org/~niemisto/Introduction%20to%20SCL.pptx Introduction to SCL]&lt;br /&gt;
* [[SCL Compiler]]&lt;br /&gt;
* [[SCL Tutorial]]&lt;br /&gt;
* [[SCL Types]]&lt;br /&gt;
&amp;lt;!--* [[SCL_Language|SCL Language]] --&amp;gt;&lt;br /&gt;
&amp;lt;!--* [https://www.simantics.org/wiki/index.php/Org.simantics.scl_Compiler SCL Compiler]--&amp;gt;&lt;br /&gt;
* [[Org.simantics.objmap_Manual|Object Map Manual]]&lt;br /&gt;
* [[SCL Registry]]&lt;br /&gt;
* [http://www.simantics.org/SCLDocumentation/StandardLibrary/Prelude.html SCL Reference]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Model Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Structural Ontology]]&lt;br /&gt;
* [[Users and Roles]]&lt;br /&gt;
* [[Models]]&lt;br /&gt;
* [[Concept Versioning]]&lt;br /&gt;
* [[Component Identification]]&lt;br /&gt;
* [[Tutorial: Model Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Project Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Project Management Conceptual Model]]&lt;br /&gt;
* [[Project Development]]&lt;br /&gt;
* [[Tutorial: Project Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Diagram Development ===&lt;br /&gt;
&lt;br /&gt;
* [[2D Ontologies]]&lt;br /&gt;
* [[org.simantics.diagram|Diagram]]&lt;br /&gt;
* [[org.simantics.scenegraph|Scene graph]]&lt;br /&gt;
* [[Diagram connections]]&lt;br /&gt;
* [[Tutorial: Diagram Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Issue Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Issue subsystem general description]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
-----&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3180</id>
		<title>Simantics Developer Documentation</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3180"/>
		<updated>2015-06-25T11:41:04Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Simantics Constraint Language */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
[[image:Simantics_logo_pile_01.png|right|border|400px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Simantics&#039;&#039;&#039; is a software platform for modelling and simulation. The system has client-server architecture with a semantic ontology-based modelling database and Eclipse framework -based client software with plug-in interface. The Simantics platform and many of its components are open source under [http://www.eclipse.org/legal/epl-v10.html Eclipse Public License (EPL)].&lt;br /&gt;
&lt;br /&gt;
The philosophy of the Simantics platform is to offer an open, high level application platform on which different computational tools can be easily integrated to form a common environment for modelling and simulation. The platform includes several modelling tools, so-called editors, for e.g. 2D graph-like hierarchical model composition and semantic graph browsing.&lt;br /&gt;
&lt;br /&gt;
One of the biggest innovations in the Simantics platform is the semantic modelling approach itself and high-level ontology tools. The semantic database, i.e. triplestore, on the server side enables high performance data management and arbitrary mappings of data. This enables e.g. efficient mapping of simulation and measurement data to the model configuration and its visualisation.&lt;br /&gt;
&lt;br /&gt;
The Simantics development and maintenance process is built to be solid and scalable from the very beginning. The objective is to aim far to the future what comes to requirements for scalability, usability, and reliability.&lt;br /&gt;
&lt;br /&gt;
This &#039;&#039;Simantics Developer Documentation&#039;&#039; is targeted to programmers and software developers developing either the platform itself or additional plug-ins to be used with or on the platform. The [[userwiki:Main_Page|Simantics End User Documentation]] complements to documentation for the Simantics platform offering overview and detailed information about the platform from the user&#039;s point of view. The [https://www.simantics.org/simantics Simantics] website is the source of information for the Simantics project and related subjects[[Tutorials|.]]&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:white;&amp;quot;&amp;gt;Disclaimer Warning: This site may cause narcolepsia in some readers. Consult your doctor if sensitive to boredom.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;75%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
* [[Glossary]]&lt;br /&gt;
* [[Introduction to Simantics Architecture]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Data View]]&lt;br /&gt;
* [[Component View]]&lt;br /&gt;
* [[Licensing|Licensing]]&lt;br /&gt;
* [[Useful Links]]&lt;br /&gt;
&amp;lt;!--* [[Simantics Specifications|Specifications]]--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Documents ===&lt;br /&gt;
&lt;br /&gt;
* [[Quick Development Environment Setup|Quick Development Environment Setup Guide]]&lt;br /&gt;
* [[Target Platform]]&lt;br /&gt;
* [[Development Practices]]&lt;br /&gt;
* [[Internalization]]&lt;br /&gt;
* [[Update Site]]&lt;br /&gt;
* [[Coding Convention]]&lt;br /&gt;
* [[Tools]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
* [[FAQ]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Ontology Development ===&lt;br /&gt;
&lt;br /&gt;
* [[:Media:Layer0.pdf|Layer0.pdf]] ([[:File:Layer0.pdf|log]])&lt;br /&gt;
* [[Graph Compiler]]&lt;br /&gt;
* [[Transferable Graph]]&lt;br /&gt;
* [[Binary Container Format]]&lt;br /&gt;
* [[Graph File Format]]&lt;br /&gt;
* [[Version Migration]]&lt;br /&gt;
* [[Tutorial: Ontology Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Database Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Interface summary]]&lt;br /&gt;
* [[Tutorial: Quickstart]]&lt;br /&gt;
* [[Tutorial: Database Development]]&lt;br /&gt;
* [[Resource Adaptation]]&lt;br /&gt;
* [[Resource Serialization]]&lt;br /&gt;
* [[Inverse Relations]]&lt;br /&gt;
* [[Virtual Graphs]]&lt;br /&gt;
* [[Functions]]&lt;br /&gt;
* [[Procedural Values]]&lt;br /&gt;
* [[Variable]]&lt;br /&gt;
* [[Undo Mechanism]]&lt;br /&gt;
* [[Team Features]]&lt;br /&gt;
* [[Subgraph Extents]]&lt;br /&gt;
* [[Database Testing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Data management &amp;amp; Experiment Control ===&lt;br /&gt;
&lt;br /&gt;
* [[Databoard Specification]]&lt;br /&gt;
* [[Databoard Developer Manual|Databoard Java Manual]]&lt;br /&gt;
* [[Experiment Control]]&lt;br /&gt;
* [[Dataflows]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== UI Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Org.simantics.browsing.ui_Manual|Browser Manual]]&lt;br /&gt;
* [[org.simantics.browsing.ui.feature|Browser Component]]&lt;br /&gt;
* [[Org.simantics.scenegraph.loader|Scene Graph Loader]]&lt;br /&gt;
* [[Org.simantics.message|Messages]]&lt;br /&gt;
* [[Org.simantics.views|Modelled Views]]&lt;br /&gt;
* [[Org.simantics.document|Documents]]&lt;br /&gt;
* [[Selection View]]&lt;br /&gt;
|}&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Simantics Constraint Language===&lt;br /&gt;
&lt;br /&gt;
* [[SCL Compiler]]&lt;br /&gt;
* [[SCL Tutorial]]&lt;br /&gt;
* [[SCL Types]]&lt;br /&gt;
&amp;lt;!--* [[SCL_Language|SCL Language]] --&amp;gt;&lt;br /&gt;
&amp;lt;!--* [https://www.simantics.org/wiki/index.php/Org.simantics.scl_Compiler SCL Compiler]--&amp;gt;&lt;br /&gt;
* [[Org.simantics.objmap_Manual|Object Map Manual]]&lt;br /&gt;
* [[SCL Registry]]&lt;br /&gt;
* [http://www.simantics.org/SCLDocumentation/StandardLibrary/Prelude.html SCL Reference]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Model Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Structural Ontology]]&lt;br /&gt;
* [[Users and Roles]]&lt;br /&gt;
* [[Models]]&lt;br /&gt;
* [[Concept Versioning]]&lt;br /&gt;
* [[Tutorial: Model Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Project Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Project Management Conceptual Model]]&lt;br /&gt;
* [[Project Development]]&lt;br /&gt;
* [[Tutorial: Project Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Diagram Development ===&lt;br /&gt;
&lt;br /&gt;
* [[2D Ontologies]]&lt;br /&gt;
* [[org.simantics.diagram|Diagram]]&lt;br /&gt;
* [[org.simantics.scenegraph|Scene graph]]&lt;br /&gt;
* [[Diagram connections]]&lt;br /&gt;
* [[Tutorial: Diagram Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Issue Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Issue subsystem general description]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
-----&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3179</id>
		<title>Simantics Developer Documentation</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Simantics_Developer_Documentation&amp;diff=3179"/>
		<updated>2015-06-25T11:37:17Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Simantics Constraint Language */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
[[image:Simantics_logo_pile_01.png|right|border|400px]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Simantics&#039;&#039;&#039; is a software platform for modelling and simulation. The system has client-server architecture with a semantic ontology-based modelling database and Eclipse framework -based client software with plug-in interface. The Simantics platform and many of its components are open source under [http://www.eclipse.org/legal/epl-v10.html Eclipse Public License (EPL)].&lt;br /&gt;
&lt;br /&gt;
The philosophy of the Simantics platform is to offer an open, high level application platform on which different computational tools can be easily integrated to form a common environment for modelling and simulation. The platform includes several modelling tools, so-called editors, for e.g. 2D graph-like hierarchical model composition and semantic graph browsing.&lt;br /&gt;
&lt;br /&gt;
One of the biggest innovations in the Simantics platform is the semantic modelling approach itself and high-level ontology tools. The semantic database, i.e. triplestore, on the server side enables high performance data management and arbitrary mappings of data. This enables e.g. efficient mapping of simulation and measurement data to the model configuration and its visualisation.&lt;br /&gt;
&lt;br /&gt;
The Simantics development and maintenance process is built to be solid and scalable from the very beginning. The objective is to aim far to the future what comes to requirements for scalability, usability, and reliability.&lt;br /&gt;
&lt;br /&gt;
This &#039;&#039;Simantics Developer Documentation&#039;&#039; is targeted to programmers and software developers developing either the platform itself or additional plug-ins to be used with or on the platform. The [[userwiki:Main_Page|Simantics End User Documentation]] complements to documentation for the Simantics platform offering overview and detailed information about the platform from the user&#039;s point of view. The [https://www.simantics.org/simantics Simantics] website is the source of information for the Simantics project and related subjects[[Tutorials|.]]&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:white;&amp;quot;&amp;gt;Disclaimer Warning: This site may cause narcolepsia in some readers. Consult your doctor if sensitive to boredom.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;75%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
=== Overview ===&lt;br /&gt;
&lt;br /&gt;
* [[Glossary]]&lt;br /&gt;
* [[Introduction to Simantics Architecture]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Data View]]&lt;br /&gt;
* [[Component View]]&lt;br /&gt;
* [[Licensing|Licensing]]&lt;br /&gt;
* [[Useful Links]]&lt;br /&gt;
&amp;lt;!--* [[Simantics Specifications|Specifications]]--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Miscellaneous Documents ===&lt;br /&gt;
&lt;br /&gt;
* [[Quick Development Environment Setup|Quick Development Environment Setup Guide]]&lt;br /&gt;
* [[Target Platform]]&lt;br /&gt;
* [[Development Practices]]&lt;br /&gt;
* [[Internalization]]&lt;br /&gt;
* [[Update Site]]&lt;br /&gt;
* [[Coding Convention]]&lt;br /&gt;
* [[Tools]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
* [[FAQ]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Ontology Development ===&lt;br /&gt;
&lt;br /&gt;
* [[:Media:Layer0.pdf|Layer0.pdf]] ([[:File:Layer0.pdf|log]])&lt;br /&gt;
* [[Graph Compiler]]&lt;br /&gt;
* [[Transferable Graph]]&lt;br /&gt;
* [[Binary Container Format]]&lt;br /&gt;
* [[Graph File Format]]&lt;br /&gt;
* [[Version Migration]]&lt;br /&gt;
* [[Tutorial: Ontology Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Database Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Interface summary]]&lt;br /&gt;
* [[Tutorial: Quickstart]]&lt;br /&gt;
* [[Tutorial: Database Development]]&lt;br /&gt;
* [[Resource Adaptation]]&lt;br /&gt;
* [[Resource Serialization]]&lt;br /&gt;
* [[Inverse Relations]]&lt;br /&gt;
* [[Virtual Graphs]]&lt;br /&gt;
* [[Functions]]&lt;br /&gt;
* [[Procedural Values]]&lt;br /&gt;
* [[Variable]]&lt;br /&gt;
* [[Undo Mechanism]]&lt;br /&gt;
* [[Team Features]]&lt;br /&gt;
* [[Subgraph Extents]]&lt;br /&gt;
* [[Database Testing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Data management &amp;amp; Experiment Control ===&lt;br /&gt;
&lt;br /&gt;
* [[Databoard Specification]]&lt;br /&gt;
* [[Databoard Developer Manual|Databoard Java Manual]]&lt;br /&gt;
* [[Experiment Control]]&lt;br /&gt;
* [[Dataflows]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== UI Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Org.simantics.browsing.ui_Manual|Browser Manual]]&lt;br /&gt;
* [[org.simantics.browsing.ui.feature|Browser Component]]&lt;br /&gt;
* [[Org.simantics.scenegraph.loader|Scene Graph Loader]]&lt;br /&gt;
* [[Org.simantics.message|Messages]]&lt;br /&gt;
* [[Org.simantics.views|Modelled Views]]&lt;br /&gt;
* [[Org.simantics.document|Documents]]&lt;br /&gt;
* [[Selection View]]&lt;br /&gt;
|}&lt;br /&gt;
{|width=&amp;quot;100%&amp;quot;&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Simantics Constraint Language===&lt;br /&gt;
&lt;br /&gt;
* [[SCL Compiler]]&lt;br /&gt;
* [[SCL Tutorial]]&lt;br /&gt;
* [[SCL Types]]&lt;br /&gt;
&amp;lt;!--* [[SCL_Language|SCL Language]] --&amp;gt;&lt;br /&gt;
&amp;lt;!--* [https://www.simantics.org/wiki/index.php/Org.simantics.scl_Compiler SCL Compiler]--&amp;gt;&lt;br /&gt;
* [[Org.simantics.objmap_Manual|Object Map Manual]]&lt;br /&gt;
* [[SCL Registry]]&lt;br /&gt;
* [http://www.simantics.org/SCLDocumentation/ SCL Reference]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Model Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Structural Ontology]]&lt;br /&gt;
* [[Users and Roles]]&lt;br /&gt;
* [[Models]]&lt;br /&gt;
* [[Concept Versioning]]&lt;br /&gt;
* [[Tutorial: Model Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Project Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Project Management Conceptual Model]]&lt;br /&gt;
* [[Project Development]]&lt;br /&gt;
* [[Tutorial: Project Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Diagram Development ===&lt;br /&gt;
&lt;br /&gt;
* [[2D Ontologies]]&lt;br /&gt;
* [[org.simantics.diagram|Diagram]]&lt;br /&gt;
* [[org.simantics.scenegraph|Scene graph]]&lt;br /&gt;
* [[Diagram connections]]&lt;br /&gt;
* [[Tutorial: Diagram Development]]&lt;br /&gt;
&lt;br /&gt;
|width=&amp;quot;25%&amp;quot; valign=&amp;quot;top&amp;quot;|&lt;br /&gt;
&lt;br /&gt;
=== Issue Development ===&lt;br /&gt;
&lt;br /&gt;
* [[Issue subsystem general description]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
-----&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1514</id>
		<title>Development Practices</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1514"/>
		<updated>2010-11-18T13:08:56Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Integrating Branches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&#039;&#039;If it isn&#039;t in the wiki, it doesn&#039;t exist.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using version control ==&lt;br /&gt;
&lt;br /&gt;
First things first, read through [http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html Subversion best practices].&lt;br /&gt;
&lt;br /&gt;
=== Branching ===&lt;br /&gt;
&lt;br /&gt;
In Simantics, only new major releases may contain breaking changes. Therefore in Simantics we strive to use a specialization of the &#039;&#039;Branch-When-Needed&#039;&#039; system, i.e. &#039;&#039;&#039;Branch-Every-Major-Change&#039;&#039;&#039;. This allows us to keep continuous builds (hudson) working with less disruption, and enables easier pre-release testing, migration and peer review.&lt;br /&gt;
&lt;br /&gt;
The rules are:&lt;br /&gt;
* Users commit their day-to-day work on /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #1&#039;&#039;&#039;: /trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;br /&gt;
* &#039;&#039;&#039;Rule #2&#039;&#039;&#039;: a single commit (changeset) must not be so large so as to discourage peer-review.&lt;br /&gt;
* &#039;&#039;&#039;Rule #3&#039;&#039;&#039;: if rules #1 and #2 come into conflict (i.e. it&#039;s impossible to make a series of small commits without disrupting the trunk), then the user should create a branch and commit a series of smaller changesets there. This allows peer-review without disrupting the stability of /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #4&#039;&#039;&#039;: if API is changed, old version in the trunk must be tagged, and version number of the trunk must be increased. If API changes break other trunk code, development must continue in its own branch. Non-incremental change in an ontology is counted as major change (prevents using existing databases); new branch must be created.&lt;br /&gt;
&lt;br /&gt;
;Pros: /trunk is guaranteed to be stable at all times. The hassle of branching/merging is somewhat rare.&lt;br /&gt;
&lt;br /&gt;
The word &#039;&#039;&#039;stable&#039;&#039;&#039; here implies mainly API stability but also functional stability. Functional stability must be enforced through both automatic and manual testing. If there are no test cases, functional stability becomes really hard to enforce. Therefore testing is key. &lt;br /&gt;
&lt;br /&gt;
Violating these rules will result removal of your breaking commits from the SVN.&lt;br /&gt;
&lt;br /&gt;
=== Integrating Branches ===&lt;br /&gt;
We obviously do not want development to continue eternally in branches so that changes are never merged between branches or integrated back to trunk. Branches are usually private or shared between a group of developers that work on a particular task. The process for integration to trunk is as follows:&lt;br /&gt;
* The Simantics Technical Board and its weekly meetings will be the place for the developers to advertise and present their changes to the board.&lt;br /&gt;
* The following things need to be documented for the changes in some way:&lt;br /&gt;
** The &#039;&#039;&#039;what&#039;&#039;&#039; and &#039;&#039;&#039;why&#039;&#039;&#039; for the changes&lt;br /&gt;
** Migration instructions from previous version (trunk)&lt;br /&gt;
** When intergation is done, mail must be send to [mailto:simantics-developers@lists.simantics.org Simantics developers list] about the change.&lt;br /&gt;
** ...&lt;br /&gt;
&lt;br /&gt;
 TODO more description&lt;br /&gt;
&lt;br /&gt;
=== Versioning ===&lt;br /&gt;
&lt;br /&gt;
In Eclipse/OSGi conventions, components (bundles, plug-ins) are versioned &amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;service&amp;gt;[.&amp;lt;qualifier&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
Our approach to component versioning is as follows:&lt;br /&gt;
* All components are in one of two states: &#039;&#039;&#039;incubation&#039;&#039;&#039; or &#039;&#039;&#039;production&#039;&#039;&#039;&lt;br /&gt;
* Incubation components: &amp;lt;major&amp;gt; = 0, API breakage is allowed between &amp;lt;minor&amp;gt; versions&lt;br /&gt;
* Production components: &amp;lt;major&amp;gt; &amp;amp;ge; 1, API breakage is allowed between &amp;lt;major&amp;gt; versions&lt;br /&gt;
&lt;br /&gt;
== Creating a new plugin ==&lt;br /&gt;
&lt;br /&gt;
Before a release, the plugin is in incubation phase and there are no quality or other requirements. The repository https://www.simulationsite.net/svn/simantics-incubator may be used to share or co-develop the plugin with other developers, but&lt;br /&gt;
the plugin must not be included in the features defined in https://www.simulationsite.net/svn/simantics repository.&lt;br /&gt;
&lt;br /&gt;
If the new plugin is a result of refactoring some already existing plugin into two pieces or otherwise is closely related to an other plugin under development, the new plugin can be committed to the same branch of https://www.simulationsite.net/svn/simantics where the other plugin is developed in. However, unreleased plugins should not be committed to trunk.&lt;br /&gt;
&lt;br /&gt;
=== Naming a plugin ===&lt;br /&gt;
&lt;br /&gt;
If the plugin is intended to be part of the official Simantics release, its name should begin with &#039;&#039;org.simantics&#039;&#039; followed by a word that describes the plugin. If the functionality of the same domain is divided into multiple plugins, the name may have more parts. The following suffixes are used:&lt;br /&gt;
* &#039;&#039;.feature&#039;&#039; for feature projects.&lt;br /&gt;
* &#039;&#039;.product&#039;&#039; A plugin defining a product.&lt;br /&gt;
* &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; Provides UI-functionality for &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;. Separating base functionality and UI (that depends on SWT) is usually recommendable so that headless applications do not have unnecessary dependencies.&lt;br /&gt;
** Example: org.simantics.simulation, org.simantics.simulation.ui&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE!&#039;&#039;&#039; If the the UI is light (e.g. wizards, dialogs, renderers, few external dependencies) the UI code can reside in &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;, a separate &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; is not required. In such a case, the UI dependencies (to plugins such as &#039;&#039;org.eclipse.swt&#039;&#039;) are &#039;&#039;optional&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Publising a standalone plugin ==&lt;br /&gt;
&lt;br /&gt;
# Ensure that the plugin satisfies the following quality requirements:&lt;br /&gt;
#* The plugin contains no compilation errors (against which dependencies???)&lt;br /&gt;
#* All public classes and interfaces are documented (javadoc)&lt;br /&gt;
#* Each public package contains a package-info.java containing package-related comments and annotations (see [http://java.sun.com/docs/books/jls/third_edition/html/packages.html] &#039;&#039;chapter 7.4&#039;&#039;)&lt;br /&gt;
#* examples/&lt;br /&gt;
#* unittests/&lt;br /&gt;
#* Version information&lt;br /&gt;
#* (optional) Build Script (targets: &#039;&#039;clean&#039;&#039;, &#039;&#039;build&#039;&#039;, &#039;&#039;clean-build&#039;&#039;)&lt;br /&gt;
#** [name]_[version]-src.zip&lt;br /&gt;
#** [name]_[version].jar &lt;br /&gt;
#** [name]_[version].zip&lt;br /&gt;
#*** doc/&lt;br /&gt;
#**** manual.pdf&lt;br /&gt;
#**** changelog.txt&lt;br /&gt;
#*** examples/&lt;br /&gt;
#*** unittests/&lt;br /&gt;
#*** javadoc/ (&#039;&#039;optional&#039;&#039;)&lt;br /&gt;
#*** [name]_[version]-src.zip&lt;br /&gt;
#*** [name]_[version].jar&lt;br /&gt;
#** [name]_[version]-project.zip (Contains everything in workspace)&lt;br /&gt;
#** See Example: [[svn:tagi/org.simantics.datatype/trunk/build.xml|Non-OSGi]], [[svn:tagi/org.simantics.data/trunk/build2.xml|OSGi]] &lt;br /&gt;
# Create a homepage for the plugin in wiki (for example [[org.simantics.datatype]]) that contains:&lt;br /&gt;
#* Development documentation that is not written in javadoc (basic concepts, components etc.) [We should discuss more about what and how to document] and links to user documentation if the plugin contributes new user interfaces.&lt;br /&gt;
#* Change log&lt;br /&gt;
#* Plugin roadmap&lt;br /&gt;
#* Who are responsible for the plugin&lt;br /&gt;
#* (optional) Download to artifacts created by Build script&lt;br /&gt;
# Commit the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/trunk&lt;br /&gt;
# Create a tag of the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/tags/&amp;lt;version&amp;gt;&lt;br /&gt;
# Inform other developers about the new plugin in [simantics-developers@simantics.org]. See also [[Mailing Lists]].&lt;br /&gt;
&lt;br /&gt;
=== Including a new plug-in to existing features ===&lt;br /&gt;
&lt;br /&gt;
Inclusion of a plug-in in a feature must always be carefully considered. Consider the following before including anything:&lt;br /&gt;
* &#039;&#039;&#039;Cohesion&#039;&#039;&#039;: Does the plug-in logically belong in the considered feature.xml?&lt;br /&gt;
* &#039;&#039;&#039;Dependencies&#039;&#039;&#039;: What does the new plug-in depend on? Which dependencies are optional? Do the dependencies of the feature&#039;s other plug-ins intersect naturally with those of the new plug-in?&lt;br /&gt;
* &#039;&#039;&#039;Permission&#039;&#039;&#039;: do not add anything without permission from the feature maintainer or send a patch and hope it will be merged.&lt;br /&gt;
&lt;br /&gt;
Note that it is not mandatory that each plug-in only resides in one feature. Having multiple features including the same plug-in will not break a PDE build.&lt;br /&gt;
&lt;br /&gt;
Modifying a feature will most likely break:&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* TODO: link to instructions for general hudson and pde build configuration&lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: add a line for the new plug-in in all project sets that include the modified feature&lt;br /&gt;
&lt;br /&gt;
== Releasing a new version of a plugin == &lt;br /&gt;
&lt;br /&gt;
# Increment version number, incl. plugin.xml, build.xml, homepage. Bug fixes increment minor number, API changes major number.&lt;br /&gt;
# Run test cases or test suite&lt;br /&gt;
# Check java docs are compiled without errors. Read Javadocs&lt;br /&gt;
# Update homepage&lt;br /&gt;
# (optional) run build.xml and upload generated artifacts to homepage&lt;br /&gt;
# Create SVN tag: trunk/ &amp;amp;rarr; tags/[version]&lt;br /&gt;
# Inform other developers [simantics-developers@simantics.org] ([[Mailing Lists]]).&lt;br /&gt;
&lt;br /&gt;
== Making refactorizations that affect other plugins ==&lt;br /&gt;
&lt;br /&gt;
# Plan refactorization beforehand with the maintainers of all affected plugins&lt;br /&gt;
# Create a new branch for all affected plugins&lt;br /&gt;
# Refactor, different possibilities&lt;br /&gt;
#* One person refactors all plugins&lt;br /&gt;
#* Every maintainer refactors his/her own plugins&lt;br /&gt;
#** Create rename scripts for other maintainers to help them&lt;br /&gt;
# Check that everything works&lt;br /&gt;
# If changes were large inform other developers in the mailing list&lt;br /&gt;
# Commit plugins to trunk&lt;br /&gt;
&lt;br /&gt;
== Developing and maintaining a released plugin ==&lt;br /&gt;
&lt;br /&gt;
Generally, people need to be able to commit their changes continuously to the SVN location dedicated for a component. Often committing is necessary for transferring their changes to another machine or just to keep their code safe. We can&#039;t allow developers committing API changes or broken temporary code into SVN locations that other projects are using - those need to be stable to some degree. Hence, the active development and API breaking &#039;&#039;&#039;must&#039;&#039;&#039; occur in SVN locations that are documented to be unstable and modifiable only by component maintainer(s). These locations shall be released to the general public according to the roadmap of the component. For every release, a &#039;&#039;tag&#039;&#039; shall be created. For every release external dependencies need to be documented: component name, version to use (tag). Releases are versioned. Version numbers are composed of three (3) segments: 3 integers and a string respectively named major.minor.service. Read [http://wiki.eclipse.org/index.php/Version_Numbering] and [http://wiki.eclipse.org/Evolving_Java-based_APIs].&lt;br /&gt;
&lt;br /&gt;
# the major segment indicates breakage in the API&lt;br /&gt;
# the minor segment indicates &amp;quot;externally visible&amp;quot; changes&lt;br /&gt;
# the service segment indicates bug fixes and the change of development stream (the semantics attached to development stream is new to this proposal, see below) &lt;br /&gt;
&lt;br /&gt;
By default, the following SVN layout should be used for components:&lt;br /&gt;
: component/&lt;br /&gt;
:: trunk/&lt;br /&gt;
:::* The main development branch, unstable by nature. This version should only be used by active developers of this component.&lt;br /&gt;
:: branches/&lt;br /&gt;
:::* Branches should be created:&lt;br /&gt;
:::** when preparing for a release, for stabilizing the component while letting active development run along in &#039;&#039;trunk&#039;&#039;.&lt;br /&gt;
:::** for working on bug-fix releases.&lt;br /&gt;
:::** when working on a larger changes, trying out things or working with other developers. These kinds of branches should either be integrated back to where they were branched from or removed as obsolete.&lt;br /&gt;
:: tags/&lt;br /&gt;
:::* Released versions of the component. Other developers and project-sets should be using these for development if the component isn&#039;t already deployed into the target platform or it is necessary to have the code in your workspace for some other reason.&lt;br /&gt;
&lt;br /&gt;
Developers may initially feel that creating tickets for every measly issue is too time consuming but it is necessary to make any kind of change tracking possible for releases. Obviously during the initial development of a component the code changes a lot and all the time. This is exactly why we have an &#039;&#039;incubator&#039;&#039; for starting projects that does not impose these strict rules but is more like a playground where the developer can freely &amp;quot;hack around&amp;quot; disregarding all these policies. When the developer feels his component is ready for consumption of the general public and the component passes peer review, it shall be ceremonially transferred from incubation into the official project. Each component should have documentation, unit tests and possibly examples or &#039;&#039;&#039;really good&#039;&#039;&#039; reasons for not having any.&lt;br /&gt;
&lt;br /&gt;
== Modifying the target platform ==&lt;br /&gt;
&lt;br /&gt;
The target platform is a composition of features and plug-ins that contains all the bundles that you as a developer can build your code against when starting from a blank table. It is a mixture of the standard Eclipse RCP platform, other general Eclipse components and also some Simantics components.&lt;br /&gt;
&lt;br /&gt;
It makes sense to deploy into the target platform only if your plug-ins:&lt;br /&gt;
* are general, i.e. reusable by many other components&lt;br /&gt;
* have little dependencies&lt;br /&gt;
* are stable, both by API and functionally&lt;br /&gt;
&lt;br /&gt;
Deploying plug-ins into the target platform will most likely break:&lt;br /&gt;
&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* Remove the deployed plug-ins from the plugins/ directory of the build structure to take the deployed plug-ins from the target platform&lt;br /&gt;
#* The target platform(s) used by the builds must be updated&lt;br /&gt;
#* TODO: link to instructions for general hudson and PDE build configuration &lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: remove lines matching the plug-ins that were moved into the target platform&lt;br /&gt;
&lt;br /&gt;
=== Deploying plug-ins for the target platform ===&lt;br /&gt;
&lt;br /&gt;
;Standard Procedure:&lt;br /&gt;
# Read the instructions below and deploy your plug-ins and features as P2 repositories&lt;br /&gt;
# Test your deployed components with the standard Simantics Workbench application (search for simantics-workbench.product in your development workspace)&lt;br /&gt;
# After testing your deployed versions, make your built P2 repository available on the internet and notify the [[Target Platform#Maintainer|target platform maintainer]] to grab your changes and update the official target platform.&lt;br /&gt;
&lt;br /&gt;
There are two main ways of deploying for the target platform:&lt;br /&gt;
* deploying plug-ins and fragments directly&lt;br /&gt;
* deploying plug-ins and fragments through features&lt;br /&gt;
&lt;br /&gt;
These steps can be performed using the Eclipse &#039;&#039;export wizard&#039;&#039; through the &#039;&#039;Plug-in Development/Deployable features&#039;&#039; and &#039;&#039;Plug-in Development/Deployable plug-ins and fragments&#039;&#039; wizards&lt;br /&gt;
&lt;br /&gt;
When considering whether your component should have a feature or not, consider these points:&lt;br /&gt;
* Eclipse products/applications are always made up of either a set of features or a set of plug-ins. In order for someone to use your component in an product, either your features or your plug-ins need to be included somewhere in the product. If a product is using features and you don&#039;t provide one, the product either has to create a new feature and include it or include your plug-ins in his own features.&lt;br /&gt;
* Features can be used as a way to give a collective version all plug-ins of a component. The feature will identify the versions of its included plug-ins but these need not be identical to the feature version. Not all plug-ins have to change versions while a feature version changes each time a new release of the component is made.&lt;br /&gt;
** &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: The feature deployment build will produce a &#039;&#039;P2 repository&#039;&#039; containing &#039;&#039;content.jar&#039;&#039;, &#039;&#039;artifacts.jar&#039;&#039; and two directories, &#039;&#039;features/&#039;&#039; and &#039;&#039;plugins/&#039;&#039;. The features-directory will contain the feature as JAR files which is correct when used as a P2 repository. But if you want to install your deployed features into the current target platforms, the feature jars must be unpacked with the JAR file names as the directory names&#039; &#039;&#039;&#039;Don&#039;t unpack directly into the features directory&#039;&#039;&#039;, the feature JARs do not contain a common parent folder. For example, if you&#039;ve built your feature with an ID &#039;&#039;&#039;my.feature&#039;&#039;&#039; and version &#039;&#039;&#039;1.0.0&#039;&#039;&#039;, the build will produce a file &#039;&#039;&#039;my.feature_1.0.0.jar&#039;&#039;&#039;. The contents of this jar must be unpacked into &#039;&#039;&#039;features/my.feature_1.0.0/&#039;&#039;&#039;. If you copied the JAR files into the features directory and unpack them there, &#039;&#039;&#039;do not leave the JARs in the features directory&#039;&#039;&#039;. This will also break the features.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1513</id>
		<title>Development Practices</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1513"/>
		<updated>2010-11-18T13:07:45Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Integrating Branches */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&#039;&#039;If it isn&#039;t in the wiki, it doesn&#039;t exist.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using version control ==&lt;br /&gt;
&lt;br /&gt;
First things first, read through [http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html Subversion best practices].&lt;br /&gt;
&lt;br /&gt;
=== Branching ===&lt;br /&gt;
&lt;br /&gt;
In Simantics, only new major releases may contain breaking changes. Therefore in Simantics we strive to use a specialization of the &#039;&#039;Branch-When-Needed&#039;&#039; system, i.e. &#039;&#039;&#039;Branch-Every-Major-Change&#039;&#039;&#039;. This allows us to keep continuous builds (hudson) working with less disruption, and enables easier pre-release testing, migration and peer review.&lt;br /&gt;
&lt;br /&gt;
The rules are:&lt;br /&gt;
* Users commit their day-to-day work on /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #1&#039;&#039;&#039;: /trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;br /&gt;
* &#039;&#039;&#039;Rule #2&#039;&#039;&#039;: a single commit (changeset) must not be so large so as to discourage peer-review.&lt;br /&gt;
* &#039;&#039;&#039;Rule #3&#039;&#039;&#039;: if rules #1 and #2 come into conflict (i.e. it&#039;s impossible to make a series of small commits without disrupting the trunk), then the user should create a branch and commit a series of smaller changesets there. This allows peer-review without disrupting the stability of /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #4&#039;&#039;&#039;: if API is changed, old version in the trunk must be tagged, and version number of the trunk must be increased. If API changes break other trunk code, development must continue in its own branch. Non-incremental change in an ontology is counted as major change (prevents using existing databases); new branch must be created.&lt;br /&gt;
&lt;br /&gt;
;Pros: /trunk is guaranteed to be stable at all times. The hassle of branching/merging is somewhat rare.&lt;br /&gt;
&lt;br /&gt;
The word &#039;&#039;&#039;stable&#039;&#039;&#039; here implies mainly API stability but also functional stability. Functional stability must be enforced through both automatic and manual testing. If there are no test cases, functional stability becomes really hard to enforce. Therefore testing is key. &lt;br /&gt;
&lt;br /&gt;
Violating these rules will result removal of your breaking commits from the SVN.&lt;br /&gt;
&lt;br /&gt;
=== Integrating Branches ===&lt;br /&gt;
We obviously do not want development to continue eternally in branches so that changes are never merged between branches or integrated back to trunk. Branches are usually private or shared between a group of developers that work on a particular task. The process for integration to trunk is as follows:&lt;br /&gt;
* The Simantics Technical Board and its weekly meetings will be the place for the developers to advertise and present their changes to the board.&lt;br /&gt;
* The following things need to be documented for the changes in some way:&lt;br /&gt;
** The &#039;&#039;&#039;what&#039;&#039;&#039; and &#039;&#039;&#039;why&#039;&#039;&#039; for the changes&lt;br /&gt;
** Migration instructions from previous version (trunk)&lt;br /&gt;
** Mail must be send to [mailto:simantics-developers@lists.simantics.org Simantics developers list] about the change.&lt;br /&gt;
** ...&lt;br /&gt;
&lt;br /&gt;
 TODO more description&lt;br /&gt;
&lt;br /&gt;
=== Versioning ===&lt;br /&gt;
&lt;br /&gt;
In Eclipse/OSGi conventions, components (bundles, plug-ins) are versioned &amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;service&amp;gt;[.&amp;lt;qualifier&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
Our approach to component versioning is as follows:&lt;br /&gt;
* All components are in one of two states: &#039;&#039;&#039;incubation&#039;&#039;&#039; or &#039;&#039;&#039;production&#039;&#039;&#039;&lt;br /&gt;
* Incubation components: &amp;lt;major&amp;gt; = 0, API breakage is allowed between &amp;lt;minor&amp;gt; versions&lt;br /&gt;
* Production components: &amp;lt;major&amp;gt; &amp;amp;ge; 1, API breakage is allowed between &amp;lt;major&amp;gt; versions&lt;br /&gt;
&lt;br /&gt;
== Creating a new plugin ==&lt;br /&gt;
&lt;br /&gt;
Before a release, the plugin is in incubation phase and there are no quality or other requirements. The repository https://www.simulationsite.net/svn/simantics-incubator may be used to share or co-develop the plugin with other developers, but&lt;br /&gt;
the plugin must not be included in the features defined in https://www.simulationsite.net/svn/simantics repository.&lt;br /&gt;
&lt;br /&gt;
If the new plugin is a result of refactoring some already existing plugin into two pieces or otherwise is closely related to an other plugin under development, the new plugin can be committed to the same branch of https://www.simulationsite.net/svn/simantics where the other plugin is developed in. However, unreleased plugins should not be committed to trunk.&lt;br /&gt;
&lt;br /&gt;
=== Naming a plugin ===&lt;br /&gt;
&lt;br /&gt;
If the plugin is intended to be part of the official Simantics release, its name should begin with &#039;&#039;org.simantics&#039;&#039; followed by a word that describes the plugin. If the functionality of the same domain is divided into multiple plugins, the name may have more parts. The following suffixes are used:&lt;br /&gt;
* &#039;&#039;.feature&#039;&#039; for feature projects.&lt;br /&gt;
* &#039;&#039;.product&#039;&#039; A plugin defining a product.&lt;br /&gt;
* &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; Provides UI-functionality for &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;. Separating base functionality and UI (that depends on SWT) is usually recommendable so that headless applications do not have unnecessary dependencies.&lt;br /&gt;
** Example: org.simantics.simulation, org.simantics.simulation.ui&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE!&#039;&#039;&#039; If the the UI is light (e.g. wizards, dialogs, renderers, few external dependencies) the UI code can reside in &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;, a separate &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; is not required. In such a case, the UI dependencies (to plugins such as &#039;&#039;org.eclipse.swt&#039;&#039;) are &#039;&#039;optional&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Publising a standalone plugin ==&lt;br /&gt;
&lt;br /&gt;
# Ensure that the plugin satisfies the following quality requirements:&lt;br /&gt;
#* The plugin contains no compilation errors (against which dependencies???)&lt;br /&gt;
#* All public classes and interfaces are documented (javadoc)&lt;br /&gt;
#* Each public package contains a package-info.java containing package-related comments and annotations (see [http://java.sun.com/docs/books/jls/third_edition/html/packages.html] &#039;&#039;chapter 7.4&#039;&#039;)&lt;br /&gt;
#* examples/&lt;br /&gt;
#* unittests/&lt;br /&gt;
#* Version information&lt;br /&gt;
#* (optional) Build Script (targets: &#039;&#039;clean&#039;&#039;, &#039;&#039;build&#039;&#039;, &#039;&#039;clean-build&#039;&#039;)&lt;br /&gt;
#** [name]_[version]-src.zip&lt;br /&gt;
#** [name]_[version].jar &lt;br /&gt;
#** [name]_[version].zip&lt;br /&gt;
#*** doc/&lt;br /&gt;
#**** manual.pdf&lt;br /&gt;
#**** changelog.txt&lt;br /&gt;
#*** examples/&lt;br /&gt;
#*** unittests/&lt;br /&gt;
#*** javadoc/ (&#039;&#039;optional&#039;&#039;)&lt;br /&gt;
#*** [name]_[version]-src.zip&lt;br /&gt;
#*** [name]_[version].jar&lt;br /&gt;
#** [name]_[version]-project.zip (Contains everything in workspace)&lt;br /&gt;
#** See Example: [[svn:tagi/org.simantics.datatype/trunk/build.xml|Non-OSGi]], [[svn:tagi/org.simantics.data/trunk/build2.xml|OSGi]] &lt;br /&gt;
# Create a homepage for the plugin in wiki (for example [[org.simantics.datatype]]) that contains:&lt;br /&gt;
#* Development documentation that is not written in javadoc (basic concepts, components etc.) [We should discuss more about what and how to document] and links to user documentation if the plugin contributes new user interfaces.&lt;br /&gt;
#* Change log&lt;br /&gt;
#* Plugin roadmap&lt;br /&gt;
#* Who are responsible for the plugin&lt;br /&gt;
#* (optional) Download to artifacts created by Build script&lt;br /&gt;
# Commit the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/trunk&lt;br /&gt;
# Create a tag of the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/tags/&amp;lt;version&amp;gt;&lt;br /&gt;
# Inform other developers about the new plugin in [simantics-developers@simantics.org]. See also [[Mailing Lists]].&lt;br /&gt;
&lt;br /&gt;
=== Including a new plug-in to existing features ===&lt;br /&gt;
&lt;br /&gt;
Inclusion of a plug-in in a feature must always be carefully considered. Consider the following before including anything:&lt;br /&gt;
* &#039;&#039;&#039;Cohesion&#039;&#039;&#039;: Does the plug-in logically belong in the considered feature.xml?&lt;br /&gt;
* &#039;&#039;&#039;Dependencies&#039;&#039;&#039;: What does the new plug-in depend on? Which dependencies are optional? Do the dependencies of the feature&#039;s other plug-ins intersect naturally with those of the new plug-in?&lt;br /&gt;
* &#039;&#039;&#039;Permission&#039;&#039;&#039;: do not add anything without permission from the feature maintainer or send a patch and hope it will be merged.&lt;br /&gt;
&lt;br /&gt;
Note that it is not mandatory that each plug-in only resides in one feature. Having multiple features including the same plug-in will not break a PDE build.&lt;br /&gt;
&lt;br /&gt;
Modifying a feature will most likely break:&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* TODO: link to instructions for general hudson and pde build configuration&lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: add a line for the new plug-in in all project sets that include the modified feature&lt;br /&gt;
&lt;br /&gt;
== Releasing a new version of a plugin == &lt;br /&gt;
&lt;br /&gt;
# Increment version number, incl. plugin.xml, build.xml, homepage. Bug fixes increment minor number, API changes major number.&lt;br /&gt;
# Run test cases or test suite&lt;br /&gt;
# Check java docs are compiled without errors. Read Javadocs&lt;br /&gt;
# Update homepage&lt;br /&gt;
# (optional) run build.xml and upload generated artifacts to homepage&lt;br /&gt;
# Create SVN tag: trunk/ &amp;amp;rarr; tags/[version]&lt;br /&gt;
# Inform other developers [simantics-developers@simantics.org] ([[Mailing Lists]]).&lt;br /&gt;
&lt;br /&gt;
== Making refactorizations that affect other plugins ==&lt;br /&gt;
&lt;br /&gt;
# Plan refactorization beforehand with the maintainers of all affected plugins&lt;br /&gt;
# Create a new branch for all affected plugins&lt;br /&gt;
# Refactor, different possibilities&lt;br /&gt;
#* One person refactors all plugins&lt;br /&gt;
#* Every maintainer refactors his/her own plugins&lt;br /&gt;
#** Create rename scripts for other maintainers to help them&lt;br /&gt;
# Check that everything works&lt;br /&gt;
# If changes were large inform other developers in the mailing list&lt;br /&gt;
# Commit plugins to trunk&lt;br /&gt;
&lt;br /&gt;
== Developing and maintaining a released plugin ==&lt;br /&gt;
&lt;br /&gt;
Generally, people need to be able to commit their changes continuously to the SVN location dedicated for a component. Often committing is necessary for transferring their changes to another machine or just to keep their code safe. We can&#039;t allow developers committing API changes or broken temporary code into SVN locations that other projects are using - those need to be stable to some degree. Hence, the active development and API breaking &#039;&#039;&#039;must&#039;&#039;&#039; occur in SVN locations that are documented to be unstable and modifiable only by component maintainer(s). These locations shall be released to the general public according to the roadmap of the component. For every release, a &#039;&#039;tag&#039;&#039; shall be created. For every release external dependencies need to be documented: component name, version to use (tag). Releases are versioned. Version numbers are composed of three (3) segments: 3 integers and a string respectively named major.minor.service. Read [http://wiki.eclipse.org/index.php/Version_Numbering] and [http://wiki.eclipse.org/Evolving_Java-based_APIs].&lt;br /&gt;
&lt;br /&gt;
# the major segment indicates breakage in the API&lt;br /&gt;
# the minor segment indicates &amp;quot;externally visible&amp;quot; changes&lt;br /&gt;
# the service segment indicates bug fixes and the change of development stream (the semantics attached to development stream is new to this proposal, see below) &lt;br /&gt;
&lt;br /&gt;
By default, the following SVN layout should be used for components:&lt;br /&gt;
: component/&lt;br /&gt;
:: trunk/&lt;br /&gt;
:::* The main development branch, unstable by nature. This version should only be used by active developers of this component.&lt;br /&gt;
:: branches/&lt;br /&gt;
:::* Branches should be created:&lt;br /&gt;
:::** when preparing for a release, for stabilizing the component while letting active development run along in &#039;&#039;trunk&#039;&#039;.&lt;br /&gt;
:::** for working on bug-fix releases.&lt;br /&gt;
:::** when working on a larger changes, trying out things or working with other developers. These kinds of branches should either be integrated back to where they were branched from or removed as obsolete.&lt;br /&gt;
:: tags/&lt;br /&gt;
:::* Released versions of the component. Other developers and project-sets should be using these for development if the component isn&#039;t already deployed into the target platform or it is necessary to have the code in your workspace for some other reason.&lt;br /&gt;
&lt;br /&gt;
Developers may initially feel that creating tickets for every measly issue is too time consuming but it is necessary to make any kind of change tracking possible for releases. Obviously during the initial development of a component the code changes a lot and all the time. This is exactly why we have an &#039;&#039;incubator&#039;&#039; for starting projects that does not impose these strict rules but is more like a playground where the developer can freely &amp;quot;hack around&amp;quot; disregarding all these policies. When the developer feels his component is ready for consumption of the general public and the component passes peer review, it shall be ceremonially transferred from incubation into the official project. Each component should have documentation, unit tests and possibly examples or &#039;&#039;&#039;really good&#039;&#039;&#039; reasons for not having any.&lt;br /&gt;
&lt;br /&gt;
== Modifying the target platform ==&lt;br /&gt;
&lt;br /&gt;
The target platform is a composition of features and plug-ins that contains all the bundles that you as a developer can build your code against when starting from a blank table. It is a mixture of the standard Eclipse RCP platform, other general Eclipse components and also some Simantics components.&lt;br /&gt;
&lt;br /&gt;
It makes sense to deploy into the target platform only if your plug-ins:&lt;br /&gt;
* are general, i.e. reusable by many other components&lt;br /&gt;
* have little dependencies&lt;br /&gt;
* are stable, both by API and functionally&lt;br /&gt;
&lt;br /&gt;
Deploying plug-ins into the target platform will most likely break:&lt;br /&gt;
&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* Remove the deployed plug-ins from the plugins/ directory of the build structure to take the deployed plug-ins from the target platform&lt;br /&gt;
#* The target platform(s) used by the builds must be updated&lt;br /&gt;
#* TODO: link to instructions for general hudson and PDE build configuration &lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: remove lines matching the plug-ins that were moved into the target platform&lt;br /&gt;
&lt;br /&gt;
=== Deploying plug-ins for the target platform ===&lt;br /&gt;
&lt;br /&gt;
;Standard Procedure:&lt;br /&gt;
# Read the instructions below and deploy your plug-ins and features as P2 repositories&lt;br /&gt;
# Test your deployed components with the standard Simantics Workbench application (search for simantics-workbench.product in your development workspace)&lt;br /&gt;
# After testing your deployed versions, make your built P2 repository available on the internet and notify the [[Target Platform#Maintainer|target platform maintainer]] to grab your changes and update the official target platform.&lt;br /&gt;
&lt;br /&gt;
There are two main ways of deploying for the target platform:&lt;br /&gt;
* deploying plug-ins and fragments directly&lt;br /&gt;
* deploying plug-ins and fragments through features&lt;br /&gt;
&lt;br /&gt;
These steps can be performed using the Eclipse &#039;&#039;export wizard&#039;&#039; through the &#039;&#039;Plug-in Development/Deployable features&#039;&#039; and &#039;&#039;Plug-in Development/Deployable plug-ins and fragments&#039;&#039; wizards&lt;br /&gt;
&lt;br /&gt;
When considering whether your component should have a feature or not, consider these points:&lt;br /&gt;
* Eclipse products/applications are always made up of either a set of features or a set of plug-ins. In order for someone to use your component in an product, either your features or your plug-ins need to be included somewhere in the product. If a product is using features and you don&#039;t provide one, the product either has to create a new feature and include it or include your plug-ins in his own features.&lt;br /&gt;
* Features can be used as a way to give a collective version all plug-ins of a component. The feature will identify the versions of its included plug-ins but these need not be identical to the feature version. Not all plug-ins have to change versions while a feature version changes each time a new release of the component is made.&lt;br /&gt;
** &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: The feature deployment build will produce a &#039;&#039;P2 repository&#039;&#039; containing &#039;&#039;content.jar&#039;&#039;, &#039;&#039;artifacts.jar&#039;&#039; and two directories, &#039;&#039;features/&#039;&#039; and &#039;&#039;plugins/&#039;&#039;. The features-directory will contain the feature as JAR files which is correct when used as a P2 repository. But if you want to install your deployed features into the current target platforms, the feature jars must be unpacked with the JAR file names as the directory names&#039; &#039;&#039;&#039;Don&#039;t unpack directly into the features directory&#039;&#039;&#039;, the feature JARs do not contain a common parent folder. For example, if you&#039;ve built your feature with an ID &#039;&#039;&#039;my.feature&#039;&#039;&#039; and version &#039;&#039;&#039;1.0.0&#039;&#039;&#039;, the build will produce a file &#039;&#039;&#039;my.feature_1.0.0.jar&#039;&#039;&#039;. The contents of this jar must be unpacked into &#039;&#039;&#039;features/my.feature_1.0.0/&#039;&#039;&#039;. If you copied the JAR files into the features directory and unpack them there, &#039;&#039;&#039;do not leave the JARs in the features directory&#039;&#039;&#039;. This will also break the features.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1348</id>
		<title>Development Practices</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1348"/>
		<updated>2010-11-11T14:59:56Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Branching */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&#039;&#039;If it isn&#039;t in the wiki, it doesn&#039;t exist.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using version control ==&lt;br /&gt;
&lt;br /&gt;
First things first, read through [http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html Subversion best practices].&lt;br /&gt;
&lt;br /&gt;
=== Branching ===&lt;br /&gt;
&lt;br /&gt;
In Simantics, only new major releases may contain breaking changes. Therefore in Simantics we strive to use a specialization of the &#039;&#039;Branch-When-Needed&#039;&#039; system, i.e. &#039;&#039;&#039;Branch-Every-Major-Change&#039;&#039;&#039;. This allows us to keep continuous builds (hudson) working with less disruption, and enables easier pre-release testing, migration and peer review.&lt;br /&gt;
&lt;br /&gt;
The rules are:&lt;br /&gt;
* Users commit their day-to-day work on /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #1&#039;&#039;&#039;: /trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;br /&gt;
* &#039;&#039;&#039;Rule #2&#039;&#039;&#039;: a single commit (changeset) must not be so large so as to discourage peer-review.&lt;br /&gt;
* &#039;&#039;&#039;Rule #3&#039;&#039;&#039;: if rules #1 and #2 come into conflict (i.e. it&#039;s impossible to make a series of small commits without disrupting the trunk), then the user should create a branch and commit a series of smaller changesets there. This allows peer-review without disrupting the stability of /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #4&#039;&#039;&#039;: if API is changed, old version in the trunk must be tagged, and version number of the trunk must be increased. If API changes break other trunk code, development must continue in its own branch. Non-incremental change in an ontology is counted as major change (prevents using existing databases); new branch must be created.&lt;br /&gt;
&lt;br /&gt;
;Pros: /trunk is guaranteed to be stable at all times. The hassle of branching/merging is somewhat rare.&lt;br /&gt;
&lt;br /&gt;
The word &#039;&#039;&#039;stable&#039;&#039;&#039; here implies mainly API stability but also functional stability. Functional stability must be enforced through both automatic and manual testing. If there are no test cases, functional stability becomes really hard to enforce. Therefore testing is key. &lt;br /&gt;
&lt;br /&gt;
Violating these rules will result removal of your breaking commits from the SVN.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Still needs to be defined&#039;&#039;&#039;&lt;br /&gt;
When major branch is meged to trunk? Are all modules &amp;amp; plugins updated at the same time?&lt;br /&gt;
&lt;br /&gt;
=== Versioning ===&lt;br /&gt;
&lt;br /&gt;
In Eclipse/OSGi conventions, components (bundles, plug-ins) are versioned &amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;service&amp;gt;[.&amp;lt;qualifier&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
Our approach to component versioning is as follows:&lt;br /&gt;
* All components are in one of two states: &#039;&#039;&#039;incubation&#039;&#039;&#039; or &#039;&#039;&#039;production&#039;&#039;&#039;&lt;br /&gt;
* Incubation components: &amp;lt;major&amp;gt; = 0, API breakage is allowed between &amp;lt;minor&amp;gt; versions&lt;br /&gt;
* Production components: &amp;lt;major&amp;gt; &amp;amp;ge; 1, API breakage is allowed between &amp;lt;major&amp;gt; versions&lt;br /&gt;
&lt;br /&gt;
== Creating a new plugin ==&lt;br /&gt;
&lt;br /&gt;
Before a release, the plugin is in incubation phase and there are no quality or other requirements. The repository https://www.simulationsite.net/svn/simantics-incubator may be used to share or co-develop the plugin with other developers, but&lt;br /&gt;
the plugin must not be included in the features defined in https://www.simulationsite.net/svn/simantics repository.&lt;br /&gt;
&lt;br /&gt;
If the new plugin is a result of refactoring some already existing plugin into two pieces or otherwise is closely related to an other plugin under development, the new plugin can be committed to the same branch of https://www.simulationsite.net/svn/simantics where the other plugin is developed in. However, unreleased plugins should not be committed to trunk.&lt;br /&gt;
&lt;br /&gt;
=== Naming a plugin ===&lt;br /&gt;
&lt;br /&gt;
If the plugin is intended to be part of the official Simantics release, its name should begin with &#039;&#039;org.simantics&#039;&#039; followed by a word that describes the plugin. If the functionality of the same domain is divided into multiple plugins, the name may have more parts. The following suffixes are used:&lt;br /&gt;
* &#039;&#039;.feature&#039;&#039; A plugin (?) defining a feature&lt;br /&gt;
* &#039;&#039;.product&#039;&#039; A plugin defining a product.&lt;br /&gt;
* &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; Provides UI-functionality for &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;. Separating base functionality and UI (that depends on SWT) is usually recommendable so that headless applications do not have unnecessary dependencies.&lt;br /&gt;
** Example: org.simantics.simulation, org.simantics.simulation.ui&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE!&#039;&#039;&#039; If the the UI is light (e.g. wizards, dialogs, renderers, few external dependencies) the UI code can reside in &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;, a separate &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; is not required. In such a case, the UI dependencies (to plugins such as &#039;&#039;org.eclipse.swt&#039;&#039;) are &#039;&#039;optional&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Publising a standalone plugin ==&lt;br /&gt;
&lt;br /&gt;
# Ensure that the plugin satisfies the following quality requirements:&lt;br /&gt;
#* The plugin contains no compilation errors (against which dependencies???)&lt;br /&gt;
#* All public classes and interfaces are documented (javadoc)&lt;br /&gt;
#* Each public package contains a package-info.java containing package-related comments and annotations (see [http://java.sun.com/docs/books/jls/third_edition/html/packages.html] &#039;&#039;chapter 7.4&#039;&#039;)&lt;br /&gt;
#* examples/&lt;br /&gt;
#* unittests/&lt;br /&gt;
#* Version information&lt;br /&gt;
#* (optional) Build Script (targets: &#039;&#039;clean&#039;&#039;, &#039;&#039;build&#039;&#039;, &#039;&#039;clean-build&#039;&#039;)&lt;br /&gt;
#** [name]_[version]-src.zip&lt;br /&gt;
#** [name]_[version].jar &lt;br /&gt;
#** [name]_[version].zip&lt;br /&gt;
#*** doc/&lt;br /&gt;
#**** manual.pdf&lt;br /&gt;
#**** changelog.txt&lt;br /&gt;
#*** examples/&lt;br /&gt;
#*** unittests/&lt;br /&gt;
#*** javadoc/ (&#039;&#039;optional&#039;&#039;)&lt;br /&gt;
#*** [name]_[version]-src.zip&lt;br /&gt;
#*** [name]_[version].jar&lt;br /&gt;
#** [name]_[version]-project.zip (Contains everything in workspace)&lt;br /&gt;
#** See Example: [[svn:tagi/org.simantics.datatype/trunk/build.xml|Non-OSGi]], [[svn:tagi/org.simantics.data/trunk/build2.xml|OSGi]] &lt;br /&gt;
# Create a homepage for the plugin in wiki (for example [[org.simantics.datatype]]) that contains:&lt;br /&gt;
#* Development documentation that is not written in javadoc (basic concepts, components etc.) [We should discuss more about what and how to document] and links to user documentation if the plugin contributes new user interfaces.&lt;br /&gt;
#* Change log&lt;br /&gt;
#* Plugin roadmap&lt;br /&gt;
#* Who are responsible for the plugin&lt;br /&gt;
#* (optional) Download to artifacts created by Build script&lt;br /&gt;
# Commit the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/trunk&lt;br /&gt;
# Create a tag of the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/tags/&amp;lt;version&amp;gt;&lt;br /&gt;
# Inform other developers about the new plugin in [simantics-developers@simantics.org]. See also [[Mailing Lists]].&lt;br /&gt;
&lt;br /&gt;
=== Including a new plug-in to existing features ===&lt;br /&gt;
&lt;br /&gt;
Inclusion of a plug-in in a feature must always be carefully considered. Consider the following before including anything:&lt;br /&gt;
* &#039;&#039;&#039;Cohesion&#039;&#039;&#039;: Does the plug-in logically belong in the considered feature.xml?&lt;br /&gt;
* &#039;&#039;&#039;Dependencies&#039;&#039;&#039;: What does the new plug-in depend on? Which dependencies are optional? Do the dependencies of the feature&#039;s other plug-ins intersect naturally with those of the new plug-in?&lt;br /&gt;
* &#039;&#039;&#039;Permission&#039;&#039;&#039;: do not add anything without permission from the feature maintainer or send a patch and hope it will be merged.&lt;br /&gt;
&lt;br /&gt;
Note that it is not mandatory that each plug-in only resides in one feature. Having multiple features including the same plug-in will not break a PDE build.&lt;br /&gt;
&lt;br /&gt;
Modifying a feature will most likely break:&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* TODO: link to instructions for general hudson and pde build configuration&lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: add a line for the new plug-in in all project sets that include the modified feature&lt;br /&gt;
&lt;br /&gt;
== Releasing a new version of a plugin == &lt;br /&gt;
&lt;br /&gt;
# Increment version number, incl. plugin.xml, build.xml, homepage. Bug fixes increment minor number, API changes major number.&lt;br /&gt;
# Run test cases or test suite&lt;br /&gt;
# Check java docs are compiled without errors. Read Javadocs&lt;br /&gt;
# Update homepage&lt;br /&gt;
# (optional) run build.xml and upload generated artifacts to homepage&lt;br /&gt;
# Create SVN tag: trunk/ &amp;amp;rarr; tags/[version]&lt;br /&gt;
# Inform other developers [simantics-developers@simantics.org] ([[Mailing Lists]]).&lt;br /&gt;
&lt;br /&gt;
== Making refactorizations that affect other plugins ==&lt;br /&gt;
&lt;br /&gt;
# Plan refactorization beforehand with the maintainers of all affected plugins&lt;br /&gt;
# Create a new branch for all affected plugins&lt;br /&gt;
# Refactor, different possibilities&lt;br /&gt;
#* One person refactors all plugins&lt;br /&gt;
#* Every maintainer refactors his/her own plugins&lt;br /&gt;
#** Create rename scripts for other maintainers to help them&lt;br /&gt;
# Check that everything works&lt;br /&gt;
# If changes were large inform other developers in the mailing list&lt;br /&gt;
# Commit plugins to trunk&lt;br /&gt;
&lt;br /&gt;
== Developing and maintaining a released plugin ==&lt;br /&gt;
&lt;br /&gt;
Generally, people need to be able to commit their changes continuously to the SVN location dedicated for a component. Often committing is necessary for transferring their changes to another machine or just to keep their code safe. We can&#039;t allow developers committing API changes or broken temporary code into SVN locations that other projects are using - those need to be stable to some degree. Hence, the active development and API breaking &#039;&#039;&#039;must&#039;&#039;&#039; occur in SVN locations that are documented to be unstable and modifiable only by component maintainer(s). These locations shall be released to the general public according to the roadmap of the component. For every release, a &#039;&#039;tag&#039;&#039; shall be created. For every release external dependencies need to be documented: component name, version to use (tag). Releases are versioned. Version numbers are composed of three (3) segments: 3 integers and a string respectively named major.minor.service. Read [http://wiki.eclipse.org/index.php/Version_Numbering] and [http://wiki.eclipse.org/Evolving_Java-based_APIs].&lt;br /&gt;
&lt;br /&gt;
# the major segment indicates breakage in the API&lt;br /&gt;
# the minor segment indicates &amp;quot;externally visible&amp;quot; changes&lt;br /&gt;
# the service segment indicates bug fixes and the change of development stream (the semantics attached to development stream is new to this proposal, see below) &lt;br /&gt;
&lt;br /&gt;
By default, the following SVN layout should be used for components:&lt;br /&gt;
: component/&lt;br /&gt;
:: trunk/&lt;br /&gt;
:::* The main development branch, unstable by nature. This version should only be used by active developers of this component.&lt;br /&gt;
:: branches/&lt;br /&gt;
:::* Branches should be created:&lt;br /&gt;
:::** when preparing for a release, for stabilizing the component while letting active development run along in &#039;&#039;trunk&#039;&#039;.&lt;br /&gt;
:::** for working on bug-fix releases.&lt;br /&gt;
:::** when working on a larger changes, trying out things or working with other developers. These kinds of branches should either be integrated back to where they were branched from or removed as obsolete.&lt;br /&gt;
:: tags/&lt;br /&gt;
:::* Released versions of the component. Other developers and project-sets should be using these for development if the component isn&#039;t already deployed into the target platform or it is necessary to have the code in your workspace for some other reason.&lt;br /&gt;
&lt;br /&gt;
Developers may initially feel that creating tickets for every measly issue is too time consuming but it is necessary to make any kind of change tracking possible for releases. Obviously during the initial development of a component the code changes a lot and all the time. This is exactly why we have an &#039;&#039;incubator&#039;&#039; for starting projects that does not impose these strict rules but is more like a playground where the developer can freely &amp;quot;hack around&amp;quot; disregarding all these policies. When the developer feels his component is ready for consumption of the general public and the component passes peer review, it shall be ceremonially transferred from incubation into the official project. Each component should have documentation, unit tests and possibly examples or &#039;&#039;&#039;really good&#039;&#039;&#039; reasons for not having any.&lt;br /&gt;
&lt;br /&gt;
== Modifying the target platform ==&lt;br /&gt;
&lt;br /&gt;
The target platform is a composition of features and plug-ins that contains all the bundles that you as a developer can build your code against when starting from a blank table. It is a mixture of the standard Eclipse RCP platform, other general Eclipse components and also some Simantics components.&lt;br /&gt;
&lt;br /&gt;
It makes sense to deploy into the target platform only if your plug-ins:&lt;br /&gt;
* are general, i.e. reusable by many other components&lt;br /&gt;
* have little dependencies&lt;br /&gt;
* are stable, both by API and functionally&lt;br /&gt;
&lt;br /&gt;
Deploying plug-ins into the target platform will most likely break:&lt;br /&gt;
&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* Remove the deployed plug-ins from the plugins/ directory of the build structure to take the deployed plug-ins from the target platform&lt;br /&gt;
#* The target platform(s) used by the builds must be updated&lt;br /&gt;
#* TODO: link to instructions for general hudson and PDE build configuration &lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: remove lines matching the plug-ins that were moved into the target platform&lt;br /&gt;
&lt;br /&gt;
=== Deploying plug-ins for the target platform ===&lt;br /&gt;
&lt;br /&gt;
;Standard Procedure:&lt;br /&gt;
# Read the instructions below and deploy your plug-ins and features as P2 repositories&lt;br /&gt;
# Test your deployed components with the standard Simantics Workbench application (search for simantics-workbench.product in your development workspace)&lt;br /&gt;
# After testing your deployed versions, make your built P2 repository available on the internet and notify the [[Target Platform#Maintainer|target platform maintainer]] to grab your changes and update the official target platform.&lt;br /&gt;
&lt;br /&gt;
There are two main ways of deploying for the target platform:&lt;br /&gt;
* deploying plug-ins and fragments directly&lt;br /&gt;
* deploying plug-ins and fragments through features&lt;br /&gt;
&lt;br /&gt;
These steps can be performed using the Eclipse &#039;&#039;export wizard&#039;&#039; through the &#039;&#039;Plug-in Development/Deployable features&#039;&#039; and &#039;&#039;Plug-in Development/Deployable plug-ins and fragments&#039;&#039; wizards&lt;br /&gt;
&lt;br /&gt;
When considering whether your component should have a feature or not, consider these points:&lt;br /&gt;
* Eclipse products/applications are always made up of either a set of features or a set of plug-ins. In order for someone to use your component in an product, either your features or your plug-ins need to be included somewhere in the product. If a product is using features and you don&#039;t provide one, the product either has to create a new feature and include it or include your plug-ins in his own features.&lt;br /&gt;
* Features can be used as a way to give a collective version all plug-ins of a component. The feature will identify the versions of its included plug-ins but these need not be identical to the feature version. Not all plug-ins have to change versions while a feature version changes each time a new release of the component is made.&lt;br /&gt;
** &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: The feature deployment build will produce a &#039;&#039;P2 repository&#039;&#039; containing &#039;&#039;content.jar&#039;&#039;, &#039;&#039;artifacts.jar&#039;&#039; and two directories, &#039;&#039;features/&#039;&#039; and &#039;&#039;plugins/&#039;&#039;. The features-directory will contain the feature as JAR files which is correct when used as a P2 repository. But if you want to install your deployed features into the current target platforms, the feature jars must be unpacked with the JAR file names as the directory names&#039; &#039;&#039;&#039;Don&#039;t unpack directly into the features directory&#039;&#039;&#039;, the feature JARs do not contain a common parent folder. For example, if you&#039;ve built your feature with an ID &#039;&#039;&#039;my.feature&#039;&#039;&#039; and version &#039;&#039;&#039;1.0.0&#039;&#039;&#039;, the build will produce a file &#039;&#039;&#039;my.feature_1.0.0.jar&#039;&#039;&#039;. The contents of this jar must be unpacked into &#039;&#039;&#039;features/my.feature_1.0.0/&#039;&#039;&#039;. If you copied the JAR files into the features directory and unpack them there, &#039;&#039;&#039;do not leave the JARs in the features directory&#039;&#039;&#039;. This will also break the features.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1347</id>
		<title>Development Practices</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1347"/>
		<updated>2010-11-11T14:55:53Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Branching */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&#039;&#039;If it isn&#039;t in the wiki, it doesn&#039;t exist.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using version control ==&lt;br /&gt;
&lt;br /&gt;
First things first, read through [http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html Subversion best practices].&lt;br /&gt;
&lt;br /&gt;
=== Branching ===&lt;br /&gt;
&lt;br /&gt;
In Simantics, only new major releases may contain breaking changes. Therefore in Simantics we strive to use a specialization of the &#039;&#039;Branch-When-Needed&#039;&#039; system, i.e. &#039;&#039;&#039;Branch-Every-Major-Change&#039;&#039;&#039;. This allows us to keep continuous builds (hudson) working with less disruption, and enables easier pre-release testing, migration and peer review.&lt;br /&gt;
&lt;br /&gt;
The rules are:&lt;br /&gt;
* Users commit their day-to-day work on /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #1&#039;&#039;&#039;: /trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;br /&gt;
* &#039;&#039;&#039;Rule #2&#039;&#039;&#039;: a single commit (changeset) must not be so large so as to discourage peer-review.&lt;br /&gt;
* &#039;&#039;&#039;Rule #3&#039;&#039;&#039;: if rules #1 and #2 come into conflict (i.e. it&#039;s impossible to make a series of small commits without disrupting the trunk), then the user should create a branch and commit a series of smaller changesets there. This allows peer-review without disrupting the stability of /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #4&#039;&#039;&#039;: if API is changed, old version in the trunk must be tagged, and version number of the trunk must be increased. If API changes break other trunk code, development must continue in its own branch. Non-incremental change in an ontology is counted as major change (prevents using existing databases); new branch must be created.&lt;br /&gt;
&lt;br /&gt;
;Pros: /trunk is guaranteed to be stable at all times. The hassle of branching/merging is somewhat rare.&lt;br /&gt;
&lt;br /&gt;
The word &#039;&#039;&#039;stable&#039;&#039;&#039; here implies mainly API stability but also functional stability. Functional stability must be enforced through both automatic and manual testing. If there are no test cases, functional stability becomes really hard to enforce. Therefore testing is key. &lt;br /&gt;
&lt;br /&gt;
Violating these rules will result removal of your breaking commits from the SVN.&lt;br /&gt;
&lt;br /&gt;
=== Versioning ===&lt;br /&gt;
&lt;br /&gt;
In Eclipse/OSGi conventions, components (bundles, plug-ins) are versioned &amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;service&amp;gt;[.&amp;lt;qualifier&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
Our approach to component versioning is as follows:&lt;br /&gt;
* All components are in one of two states: &#039;&#039;&#039;incubation&#039;&#039;&#039; or &#039;&#039;&#039;production&#039;&#039;&#039;&lt;br /&gt;
* Incubation components: &amp;lt;major&amp;gt; = 0, API breakage is allowed between &amp;lt;minor&amp;gt; versions&lt;br /&gt;
* Production components: &amp;lt;major&amp;gt; &amp;amp;ge; 1, API breakage is allowed between &amp;lt;major&amp;gt; versions&lt;br /&gt;
&lt;br /&gt;
== Creating a new plugin ==&lt;br /&gt;
&lt;br /&gt;
Before a release, the plugin is in incubation phase and there are no quality or other requirements. The repository https://www.simulationsite.net/svn/simantics-incubator may be used to share or co-develop the plugin with other developers, but&lt;br /&gt;
the plugin must not be included in the features defined in https://www.simulationsite.net/svn/simantics repository.&lt;br /&gt;
&lt;br /&gt;
If the new plugin is a result of refactoring some already existing plugin into two pieces or otherwise is closely related to an other plugin under development, the new plugin can be committed to the same branch of https://www.simulationsite.net/svn/simantics where the other plugin is developed in. However, unreleased plugins should not be committed to trunk.&lt;br /&gt;
&lt;br /&gt;
=== Naming a plugin ===&lt;br /&gt;
&lt;br /&gt;
If the plugin is intended to be part of the official Simantics release, its name should begin with &#039;&#039;org.simantics&#039;&#039; followed by a word that describes the plugin. If the functionality of the same domain is divided into multiple plugins, the name may have more parts. The following suffixes are used:&lt;br /&gt;
* &#039;&#039;.feature&#039;&#039; A plugin (?) defining a feature&lt;br /&gt;
* &#039;&#039;.product&#039;&#039; A plugin defining a product.&lt;br /&gt;
* &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; Provides UI-functionality for &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;. Separating base functionality and UI (that depends on SWT) is usually recommendable so that headless applications do not have unnecessary dependencies.&lt;br /&gt;
** Example: org.simantics.simulation, org.simantics.simulation.ui&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE!&#039;&#039;&#039; If the the UI is light (e.g. wizards, dialogs, renderers, few external dependencies) the UI code can reside in &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;, a separate &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; is not required. In such a case, the UI dependencies (to plugins such as &#039;&#039;org.eclipse.swt&#039;&#039;) are &#039;&#039;optional&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Publising a standalone plugin ==&lt;br /&gt;
&lt;br /&gt;
# Ensure that the plugin satisfies the following quality requirements:&lt;br /&gt;
#* The plugin contains no compilation errors (against which dependencies???)&lt;br /&gt;
#* All public classes and interfaces are documented (javadoc)&lt;br /&gt;
#* Each public package contains a package-info.java containing package-related comments and annotations (see [http://java.sun.com/docs/books/jls/third_edition/html/packages.html] &#039;&#039;chapter 7.4&#039;&#039;)&lt;br /&gt;
#* examples/&lt;br /&gt;
#* unittests/&lt;br /&gt;
#* Version information&lt;br /&gt;
#* (optional) Build Script (targets: &#039;&#039;clean&#039;&#039;, &#039;&#039;build&#039;&#039;, &#039;&#039;clean-build&#039;&#039;)&lt;br /&gt;
#** [name]_[version]-src.zip&lt;br /&gt;
#** [name]_[version].jar &lt;br /&gt;
#** [name]_[version].zip&lt;br /&gt;
#*** doc/&lt;br /&gt;
#**** manual.pdf&lt;br /&gt;
#**** changelog.txt&lt;br /&gt;
#*** examples/&lt;br /&gt;
#*** unittests/&lt;br /&gt;
#*** javadoc/ (&#039;&#039;optional&#039;&#039;)&lt;br /&gt;
#*** [name]_[version]-src.zip&lt;br /&gt;
#*** [name]_[version].jar&lt;br /&gt;
#** [name]_[version]-project.zip (Contains everything in workspace)&lt;br /&gt;
#** See Example: [[svn:tagi/org.simantics.datatype/trunk/build.xml|Non-OSGi]], [[svn:tagi/org.simantics.data/trunk/build2.xml|OSGi]] &lt;br /&gt;
# Create a homepage for the plugin in wiki (for example [[org.simantics.datatype]]) that contains:&lt;br /&gt;
#* Development documentation that is not written in javadoc (basic concepts, components etc.) [We should discuss more about what and how to document] and links to user documentation if the plugin contributes new user interfaces.&lt;br /&gt;
#* Change log&lt;br /&gt;
#* Plugin roadmap&lt;br /&gt;
#* Who are responsible for the plugin&lt;br /&gt;
#* (optional) Download to artifacts created by Build script&lt;br /&gt;
# Commit the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/trunk&lt;br /&gt;
# Create a tag of the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/tags/&amp;lt;version&amp;gt;&lt;br /&gt;
# Inform other developers about the new plugin in [simantics-developers@simantics.org]. See also [[Mailing Lists]].&lt;br /&gt;
&lt;br /&gt;
=== Including a new plug-in to existing features ===&lt;br /&gt;
&lt;br /&gt;
Inclusion of a plug-in in a feature must always be carefully considered. Consider the following before including anything:&lt;br /&gt;
* &#039;&#039;&#039;Cohesion&#039;&#039;&#039;: Does the plug-in logically belong in the considered feature.xml?&lt;br /&gt;
* &#039;&#039;&#039;Dependencies&#039;&#039;&#039;: What does the new plug-in depend on? Which dependencies are optional? Do the dependencies of the feature&#039;s other plug-ins intersect naturally with those of the new plug-in?&lt;br /&gt;
* &#039;&#039;&#039;Permission&#039;&#039;&#039;: do not add anything without permission from the feature maintainer or send a patch and hope it will be merged.&lt;br /&gt;
&lt;br /&gt;
Note that it is not mandatory that each plug-in only resides in one feature. Having multiple features including the same plug-in will not break a PDE build.&lt;br /&gt;
&lt;br /&gt;
Modifying a feature will most likely break:&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* TODO: link to instructions for general hudson and pde build configuration&lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: add a line for the new plug-in in all project sets that include the modified feature&lt;br /&gt;
&lt;br /&gt;
== Releasing a new version of a plugin == &lt;br /&gt;
&lt;br /&gt;
# Increment version number, incl. plugin.xml, build.xml, homepage. Bug fixes increment minor number, API changes major number.&lt;br /&gt;
# Run test cases or test suite&lt;br /&gt;
# Check java docs are compiled without errors. Read Javadocs&lt;br /&gt;
# Update homepage&lt;br /&gt;
# (optional) run build.xml and upload generated artifacts to homepage&lt;br /&gt;
# Create SVN tag: trunk/ &amp;amp;rarr; tags/[version]&lt;br /&gt;
# Inform other developers [simantics-developers@simantics.org] ([[Mailing Lists]]).&lt;br /&gt;
&lt;br /&gt;
== Making refactorizations that affect other plugins ==&lt;br /&gt;
&lt;br /&gt;
# Plan refactorization beforehand with the maintainers of all affected plugins&lt;br /&gt;
# Create a new branch for all affected plugins&lt;br /&gt;
# Refactor, different possibilities&lt;br /&gt;
#* One person refactors all plugins&lt;br /&gt;
#* Every maintainer refactors his/her own plugins&lt;br /&gt;
#** Create rename scripts for other maintainers to help them&lt;br /&gt;
# Check that everything works&lt;br /&gt;
# If changes were large inform other developers in the mailing list&lt;br /&gt;
# Commit plugins to trunk&lt;br /&gt;
&lt;br /&gt;
== Developing and maintaining a released plugin ==&lt;br /&gt;
&lt;br /&gt;
Generally, people need to be able to commit their changes continuously to the SVN location dedicated for a component. Often committing is necessary for transferring their changes to another machine or just to keep their code safe. We can&#039;t allow developers committing API changes or broken temporary code into SVN locations that other projects are using - those need to be stable to some degree. Hence, the active development and API breaking &#039;&#039;&#039;must&#039;&#039;&#039; occur in SVN locations that are documented to be unstable and modifiable only by component maintainer(s). These locations shall be released to the general public according to the roadmap of the component. For every release, a &#039;&#039;tag&#039;&#039; shall be created. For every release external dependencies need to be documented: component name, version to use (tag). Releases are versioned. Version numbers are composed of three (3) segments: 3 integers and a string respectively named major.minor.service. Read [http://wiki.eclipse.org/index.php/Version_Numbering] and [http://wiki.eclipse.org/Evolving_Java-based_APIs].&lt;br /&gt;
&lt;br /&gt;
# the major segment indicates breakage in the API&lt;br /&gt;
# the minor segment indicates &amp;quot;externally visible&amp;quot; changes&lt;br /&gt;
# the service segment indicates bug fixes and the change of development stream (the semantics attached to development stream is new to this proposal, see below) &lt;br /&gt;
&lt;br /&gt;
By default, the following SVN layout should be used for components:&lt;br /&gt;
: component/&lt;br /&gt;
:: trunk/&lt;br /&gt;
:::* The main development branch, unstable by nature. This version should only be used by active developers of this component.&lt;br /&gt;
:: branches/&lt;br /&gt;
:::* Branches should be created:&lt;br /&gt;
:::** when preparing for a release, for stabilizing the component while letting active development run along in &#039;&#039;trunk&#039;&#039;.&lt;br /&gt;
:::** for working on bug-fix releases.&lt;br /&gt;
:::** when working on a larger changes, trying out things or working with other developers. These kinds of branches should either be integrated back to where they were branched from or removed as obsolete.&lt;br /&gt;
:: tags/&lt;br /&gt;
:::* Released versions of the component. Other developers and project-sets should be using these for development if the component isn&#039;t already deployed into the target platform or it is necessary to have the code in your workspace for some other reason.&lt;br /&gt;
&lt;br /&gt;
Developers may initially feel that creating tickets for every measly issue is too time consuming but it is necessary to make any kind of change tracking possible for releases. Obviously during the initial development of a component the code changes a lot and all the time. This is exactly why we have an &#039;&#039;incubator&#039;&#039; for starting projects that does not impose these strict rules but is more like a playground where the developer can freely &amp;quot;hack around&amp;quot; disregarding all these policies. When the developer feels his component is ready for consumption of the general public and the component passes peer review, it shall be ceremonially transferred from incubation into the official project. Each component should have documentation, unit tests and possibly examples or &#039;&#039;&#039;really good&#039;&#039;&#039; reasons for not having any.&lt;br /&gt;
&lt;br /&gt;
== Modifying the target platform ==&lt;br /&gt;
&lt;br /&gt;
The target platform is a composition of features and plug-ins that contains all the bundles that you as a developer can build your code against when starting from a blank table. It is a mixture of the standard Eclipse RCP platform, other general Eclipse components and also some Simantics components.&lt;br /&gt;
&lt;br /&gt;
It makes sense to deploy into the target platform only if your plug-ins:&lt;br /&gt;
* are general, i.e. reusable by many other components&lt;br /&gt;
* have little dependencies&lt;br /&gt;
* are stable, both by API and functionally&lt;br /&gt;
&lt;br /&gt;
Deploying plug-ins into the target platform will most likely break:&lt;br /&gt;
&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* Remove the deployed plug-ins from the plugins/ directory of the build structure to take the deployed plug-ins from the target platform&lt;br /&gt;
#* The target platform(s) used by the builds must be updated&lt;br /&gt;
#* TODO: link to instructions for general hudson and PDE build configuration &lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: remove lines matching the plug-ins that were moved into the target platform&lt;br /&gt;
&lt;br /&gt;
=== Deploying plug-ins for the target platform ===&lt;br /&gt;
&lt;br /&gt;
;Standard Procedure:&lt;br /&gt;
# Read the instructions below and deploy your plug-ins and features as P2 repositories&lt;br /&gt;
# Test your deployed components with the standard Simantics Workbench application (search for simantics-workbench.product in your development workspace)&lt;br /&gt;
# After testing your deployed versions, make your built P2 repository available on the internet and notify the [[Target Platform#Maintainer|target platform maintainer]] to grab your changes and update the official target platform.&lt;br /&gt;
&lt;br /&gt;
There are two main ways of deploying for the target platform:&lt;br /&gt;
* deploying plug-ins and fragments directly&lt;br /&gt;
* deploying plug-ins and fragments through features&lt;br /&gt;
&lt;br /&gt;
These steps can be performed using the Eclipse &#039;&#039;export wizard&#039;&#039; through the &#039;&#039;Plug-in Development/Deployable features&#039;&#039; and &#039;&#039;Plug-in Development/Deployable plug-ins and fragments&#039;&#039; wizards&lt;br /&gt;
&lt;br /&gt;
When considering whether your component should have a feature or not, consider these points:&lt;br /&gt;
* Eclipse products/applications are always made up of either a set of features or a set of plug-ins. In order for someone to use your component in an product, either your features or your plug-ins need to be included somewhere in the product. If a product is using features and you don&#039;t provide one, the product either has to create a new feature and include it or include your plug-ins in his own features.&lt;br /&gt;
* Features can be used as a way to give a collective version all plug-ins of a component. The feature will identify the versions of its included plug-ins but these need not be identical to the feature version. Not all plug-ins have to change versions while a feature version changes each time a new release of the component is made.&lt;br /&gt;
** &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: The feature deployment build will produce a &#039;&#039;P2 repository&#039;&#039; containing &#039;&#039;content.jar&#039;&#039;, &#039;&#039;artifacts.jar&#039;&#039; and two directories, &#039;&#039;features/&#039;&#039; and &#039;&#039;plugins/&#039;&#039;. The features-directory will contain the feature as JAR files which is correct when used as a P2 repository. But if you want to install your deployed features into the current target platforms, the feature jars must be unpacked with the JAR file names as the directory names&#039; &#039;&#039;&#039;Don&#039;t unpack directly into the features directory&#039;&#039;&#039;, the feature JARs do not contain a common parent folder. For example, if you&#039;ve built your feature with an ID &#039;&#039;&#039;my.feature&#039;&#039;&#039; and version &#039;&#039;&#039;1.0.0&#039;&#039;&#039;, the build will produce a file &#039;&#039;&#039;my.feature_1.0.0.jar&#039;&#039;&#039;. The contents of this jar must be unpacked into &#039;&#039;&#039;features/my.feature_1.0.0/&#039;&#039;&#039;. If you copied the JAR files into the features directory and unpack them there, &#039;&#039;&#039;do not leave the JARs in the features directory&#039;&#039;&#039;. This will also break the features.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1346</id>
		<title>Development Practices</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Development_Practices&amp;diff=1346"/>
		<updated>2010-11-11T14:24:40Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Branching */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;center&amp;gt;&#039;&#039;If it isn&#039;t in the wiki, it doesn&#039;t exist.&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using version control ==&lt;br /&gt;
&lt;br /&gt;
First things first, read through [http://svn.apache.org/repos/asf/subversion/trunk/doc/user/svn-best-practices.html Subversion best practices].&lt;br /&gt;
&lt;br /&gt;
=== Branching ===&lt;br /&gt;
&lt;br /&gt;
In Simantics, only new major releases may contain breaking changes. Therefore in Simantics we strive to use a specialization of the &#039;&#039;Branch-When-Needed&#039;&#039; system, i.e. &#039;&#039;&#039;Branch-Every-Major-Change&#039;&#039;&#039;. This allows us to keep continuous builds (hudson) working with less disruption, and enables easier pre-release testing, migration and peer review.&lt;br /&gt;
&lt;br /&gt;
The rules are:&lt;br /&gt;
* Users commit their day-to-day work on /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #1&#039;&#039;&#039;: /trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;br /&gt;
* &#039;&#039;&#039;Rule #2&#039;&#039;&#039;: a single commit (changeset) must not be so large so as to discourage peer-review.&lt;br /&gt;
* &#039;&#039;&#039;Rule #3&#039;&#039;&#039;: if rules #1 and #2 come into conflict (i.e. it&#039;s impossible to make a series of small commits without disrupting the trunk), then the user should create a branch and commit a series of smaller changesets there. This allows peer-review without disrupting the stability of /trunk.&lt;br /&gt;
* &#039;&#039;&#039;Rule #4&#039;&#039;&#039;: if API is changed, old version in the trunk must be tagged, and version number of the trunk must be increased. If API changes break other trunk code, development must continue in its own branch. Change in an ontology is counted as major change (prevents using existing databases); new branch must be created.&lt;br /&gt;
&lt;br /&gt;
;Pros: /trunk is guaranteed to be stable at all times. The hassle of branching/merging is somewhat rare.&lt;br /&gt;
&lt;br /&gt;
The word &#039;&#039;&#039;stable&#039;&#039;&#039; here implies mainly API stability but also functional stability. Functional stability must be enforced through both automatic and manual testing. If there are no test cases, functional stability becomes really hard to enforce. Therefore testing is key. &lt;br /&gt;
&lt;br /&gt;
Violating these rules will result removal of your breaking commits from the SVN.&lt;br /&gt;
&lt;br /&gt;
=== Versioning ===&lt;br /&gt;
&lt;br /&gt;
In Eclipse/OSGi conventions, components (bundles, plug-ins) are versioned &amp;lt;major&amp;gt;.&amp;lt;minor&amp;gt;.&amp;lt;service&amp;gt;[.&amp;lt;qualifier&amp;gt;].&lt;br /&gt;
&lt;br /&gt;
Our approach to component versioning is as follows:&lt;br /&gt;
* All components are in one of two states: &#039;&#039;&#039;incubation&#039;&#039;&#039; or &#039;&#039;&#039;production&#039;&#039;&#039;&lt;br /&gt;
* Incubation components: &amp;lt;major&amp;gt; = 0, API breakage is allowed between &amp;lt;minor&amp;gt; versions&lt;br /&gt;
* Production components: &amp;lt;major&amp;gt; &amp;amp;ge; 1, API breakage is allowed between &amp;lt;major&amp;gt; versions&lt;br /&gt;
&lt;br /&gt;
== Creating a new plugin ==&lt;br /&gt;
&lt;br /&gt;
Before a release, the plugin is in incubation phase and there are no quality or other requirements. The repository https://www.simulationsite.net/svn/simantics-incubator may be used to share or co-develop the plugin with other developers, but&lt;br /&gt;
the plugin must not be included in the features defined in https://www.simulationsite.net/svn/simantics repository.&lt;br /&gt;
&lt;br /&gt;
If the new plugin is a result of refactoring some already existing plugin into two pieces or otherwise is closely related to an other plugin under development, the new plugin can be committed to the same branch of https://www.simulationsite.net/svn/simantics where the other plugin is developed in. However, unreleased plugins should not be committed to trunk.&lt;br /&gt;
&lt;br /&gt;
=== Naming a plugin ===&lt;br /&gt;
&lt;br /&gt;
If the plugin is intended to be part of the official Simantics release, its name should begin with &#039;&#039;org.simantics&#039;&#039; followed by a word that describes the plugin. If the functionality of the same domain is divided into multiple plugins, the name may have more parts. The following suffixes are used:&lt;br /&gt;
* &#039;&#039;.feature&#039;&#039; A plugin (?) defining a feature&lt;br /&gt;
* &#039;&#039;.product&#039;&#039; A plugin defining a product.&lt;br /&gt;
* &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; Provides UI-functionality for &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;. Separating base functionality and UI (that depends on SWT) is usually recommendable so that headless applications do not have unnecessary dependencies.&lt;br /&gt;
** Example: org.simantics.simulation, org.simantics.simulation.ui&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE!&#039;&#039;&#039; If the the UI is light (e.g. wizards, dialogs, renderers, few external dependencies) the UI code can reside in &#039;&#039;&amp;lt;plugin&amp;gt;&#039;&#039;, a separate &#039;&#039;&amp;lt;plugin&amp;gt;.ui&#039;&#039; is not required. In such a case, the UI dependencies (to plugins such as &#039;&#039;org.eclipse.swt&#039;&#039;) are &#039;&#039;optional&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Publising a standalone plugin ==&lt;br /&gt;
&lt;br /&gt;
# Ensure that the plugin satisfies the following quality requirements:&lt;br /&gt;
#* The plugin contains no compilation errors (against which dependencies???)&lt;br /&gt;
#* All public classes and interfaces are documented (javadoc)&lt;br /&gt;
#* Each public package contains a package-info.java containing package-related comments and annotations (see [http://java.sun.com/docs/books/jls/third_edition/html/packages.html] &#039;&#039;chapter 7.4&#039;&#039;)&lt;br /&gt;
#* examples/&lt;br /&gt;
#* unittests/&lt;br /&gt;
#* Version information&lt;br /&gt;
#* (optional) Build Script (targets: &#039;&#039;clean&#039;&#039;, &#039;&#039;build&#039;&#039;, &#039;&#039;clean-build&#039;&#039;)&lt;br /&gt;
#** [name]_[version]-src.zip&lt;br /&gt;
#** [name]_[version].jar &lt;br /&gt;
#** [name]_[version].zip&lt;br /&gt;
#*** doc/&lt;br /&gt;
#**** manual.pdf&lt;br /&gt;
#**** changelog.txt&lt;br /&gt;
#*** examples/&lt;br /&gt;
#*** unittests/&lt;br /&gt;
#*** javadoc/ (&#039;&#039;optional&#039;&#039;)&lt;br /&gt;
#*** [name]_[version]-src.zip&lt;br /&gt;
#*** [name]_[version].jar&lt;br /&gt;
#** [name]_[version]-project.zip (Contains everything in workspace)&lt;br /&gt;
#** See Example: [[svn:tagi/org.simantics.datatype/trunk/build.xml|Non-OSGi]], [[svn:tagi/org.simantics.data/trunk/build2.xml|OSGi]] &lt;br /&gt;
# Create a homepage for the plugin in wiki (for example [[org.simantics.datatype]]) that contains:&lt;br /&gt;
#* Development documentation that is not written in javadoc (basic concepts, components etc.) [We should discuss more about what and how to document] and links to user documentation if the plugin contributes new user interfaces.&lt;br /&gt;
#* Change log&lt;br /&gt;
#* Plugin roadmap&lt;br /&gt;
#* Who are responsible for the plugin&lt;br /&gt;
#* (optional) Download to artifacts created by Build script&lt;br /&gt;
# Commit the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/trunk&lt;br /&gt;
# Create a tag of the plugin to https://www.simulationsite.net/svn/simantics/&amp;lt;moduleName&amp;gt;/tags/&amp;lt;version&amp;gt;&lt;br /&gt;
# Inform other developers about the new plugin in [simantics-developers@simantics.org]. See also [[Mailing Lists]].&lt;br /&gt;
&lt;br /&gt;
=== Including a new plug-in to existing features ===&lt;br /&gt;
&lt;br /&gt;
Inclusion of a plug-in in a feature must always be carefully considered. Consider the following before including anything:&lt;br /&gt;
* &#039;&#039;&#039;Cohesion&#039;&#039;&#039;: Does the plug-in logically belong in the considered feature.xml?&lt;br /&gt;
* &#039;&#039;&#039;Dependencies&#039;&#039;&#039;: What does the new plug-in depend on? Which dependencies are optional? Do the dependencies of the feature&#039;s other plug-ins intersect naturally with those of the new plug-in?&lt;br /&gt;
* &#039;&#039;&#039;Permission&#039;&#039;&#039;: do not add anything without permission from the feature maintainer or send a patch and hope it will be merged.&lt;br /&gt;
&lt;br /&gt;
Note that it is not mandatory that each plug-in only resides in one feature. Having multiple features including the same plug-in will not break a PDE build.&lt;br /&gt;
&lt;br /&gt;
Modifying a feature will most likely break:&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* TODO: link to instructions for general hudson and pde build configuration&lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: add a line for the new plug-in in all project sets that include the modified feature&lt;br /&gt;
&lt;br /&gt;
== Releasing a new version of a plugin == &lt;br /&gt;
&lt;br /&gt;
# Increment version number, incl. plugin.xml, build.xml, homepage. Bug fixes increment minor number, API changes major number.&lt;br /&gt;
# Run test cases or test suite&lt;br /&gt;
# Check java docs are compiled without errors. Read Javadocs&lt;br /&gt;
# Update homepage&lt;br /&gt;
# (optional) run build.xml and upload generated artifacts to homepage&lt;br /&gt;
# Create SVN tag: trunk/ &amp;amp;rarr; tags/[version]&lt;br /&gt;
# Inform other developers [simantics-developers@simantics.org] ([[Mailing Lists]]).&lt;br /&gt;
&lt;br /&gt;
== Making refactorizations that affect other plugins ==&lt;br /&gt;
&lt;br /&gt;
# Plan refactorization beforehand with the maintainers of all affected plugins&lt;br /&gt;
# Create a new branch for all affected plugins&lt;br /&gt;
# Refactor, different possibilities&lt;br /&gt;
#* One person refactors all plugins&lt;br /&gt;
#* Every maintainer refactors his/her own plugins&lt;br /&gt;
#** Create rename scripts for other maintainers to help them&lt;br /&gt;
# Check that everything works&lt;br /&gt;
# If changes were large inform other developers in the mailing list&lt;br /&gt;
# Commit plugins to trunk&lt;br /&gt;
&lt;br /&gt;
== Developing and maintaining a released plugin ==&lt;br /&gt;
&lt;br /&gt;
Generally, people need to be able to commit their changes continuously to the SVN location dedicated for a component. Often committing is necessary for transferring their changes to another machine or just to keep their code safe. We can&#039;t allow developers committing API changes or broken temporary code into SVN locations that other projects are using - those need to be stable to some degree. Hence, the active development and API breaking &#039;&#039;&#039;must&#039;&#039;&#039; occur in SVN locations that are documented to be unstable and modifiable only by component maintainer(s). These locations shall be released to the general public according to the roadmap of the component. For every release, a &#039;&#039;tag&#039;&#039; shall be created. For every release external dependencies need to be documented: component name, version to use (tag). Releases are versioned. Version numbers are composed of three (3) segments: 3 integers and a string respectively named major.minor.service. Read [http://wiki.eclipse.org/index.php/Version_Numbering] and [http://wiki.eclipse.org/Evolving_Java-based_APIs].&lt;br /&gt;
&lt;br /&gt;
# the major segment indicates breakage in the API&lt;br /&gt;
# the minor segment indicates &amp;quot;externally visible&amp;quot; changes&lt;br /&gt;
# the service segment indicates bug fixes and the change of development stream (the semantics attached to development stream is new to this proposal, see below) &lt;br /&gt;
&lt;br /&gt;
By default, the following SVN layout should be used for components:&lt;br /&gt;
: component/&lt;br /&gt;
:: trunk/&lt;br /&gt;
:::* The main development branch, unstable by nature. This version should only be used by active developers of this component.&lt;br /&gt;
:: branches/&lt;br /&gt;
:::* Branches should be created:&lt;br /&gt;
:::** when preparing for a release, for stabilizing the component while letting active development run along in &#039;&#039;trunk&#039;&#039;.&lt;br /&gt;
:::** for working on bug-fix releases.&lt;br /&gt;
:::** when working on a larger changes, trying out things or working with other developers. These kinds of branches should either be integrated back to where they were branched from or removed as obsolete.&lt;br /&gt;
:: tags/&lt;br /&gt;
:::* Released versions of the component. Other developers and project-sets should be using these for development if the component isn&#039;t already deployed into the target platform or it is necessary to have the code in your workspace for some other reason.&lt;br /&gt;
&lt;br /&gt;
Developers may initially feel that creating tickets for every measly issue is too time consuming but it is necessary to make any kind of change tracking possible for releases. Obviously during the initial development of a component the code changes a lot and all the time. This is exactly why we have an &#039;&#039;incubator&#039;&#039; for starting projects that does not impose these strict rules but is more like a playground where the developer can freely &amp;quot;hack around&amp;quot; disregarding all these policies. When the developer feels his component is ready for consumption of the general public and the component passes peer review, it shall be ceremonially transferred from incubation into the official project. Each component should have documentation, unit tests and possibly examples or &#039;&#039;&#039;really good&#039;&#039;&#039; reasons for not having any.&lt;br /&gt;
&lt;br /&gt;
== Modifying the target platform ==&lt;br /&gt;
&lt;br /&gt;
The target platform is a composition of features and plug-ins that contains all the bundles that you as a developer can build your code against when starting from a blank table. It is a mixture of the standard Eclipse RCP platform, other general Eclipse components and also some Simantics components.&lt;br /&gt;
&lt;br /&gt;
It makes sense to deploy into the target platform only if your plug-ins:&lt;br /&gt;
* are general, i.e. reusable by many other components&lt;br /&gt;
* have little dependencies&lt;br /&gt;
* are stable, both by API and functionally&lt;br /&gt;
&lt;br /&gt;
Deploying plug-ins into the target platform will most likely break:&lt;br /&gt;
&lt;br /&gt;
# [http://www.simantics.org/hudson Hudson PDE builds] that depend on the feature&lt;br /&gt;
#* Remove the deployed plug-ins from the plugins/ directory of the build structure to take the deployed plug-ins from the target platform&lt;br /&gt;
#* The target platform(s) used by the builds must be updated&lt;br /&gt;
#* TODO: link to instructions for general hudson and PDE build configuration &lt;br /&gt;
# [[svn:project-set/|Project sets]]&lt;br /&gt;
#* FIX: remove lines matching the plug-ins that were moved into the target platform&lt;br /&gt;
&lt;br /&gt;
=== Deploying plug-ins for the target platform ===&lt;br /&gt;
&lt;br /&gt;
;Standard Procedure:&lt;br /&gt;
# Read the instructions below and deploy your plug-ins and features as P2 repositories&lt;br /&gt;
# Test your deployed components with the standard Simantics Workbench application (search for simantics-workbench.product in your development workspace)&lt;br /&gt;
# After testing your deployed versions, make your built P2 repository available on the internet and notify the [[Target Platform#Maintainer|target platform maintainer]] to grab your changes and update the official target platform.&lt;br /&gt;
&lt;br /&gt;
There are two main ways of deploying for the target platform:&lt;br /&gt;
* deploying plug-ins and fragments directly&lt;br /&gt;
* deploying plug-ins and fragments through features&lt;br /&gt;
&lt;br /&gt;
These steps can be performed using the Eclipse &#039;&#039;export wizard&#039;&#039; through the &#039;&#039;Plug-in Development/Deployable features&#039;&#039; and &#039;&#039;Plug-in Development/Deployable plug-ins and fragments&#039;&#039; wizards&lt;br /&gt;
&lt;br /&gt;
When considering whether your component should have a feature or not, consider these points:&lt;br /&gt;
* Eclipse products/applications are always made up of either a set of features or a set of plug-ins. In order for someone to use your component in an product, either your features or your plug-ins need to be included somewhere in the product. If a product is using features and you don&#039;t provide one, the product either has to create a new feature and include it or include your plug-ins in his own features.&lt;br /&gt;
* Features can be used as a way to give a collective version all plug-ins of a component. The feature will identify the versions of its included plug-ins but these need not be identical to the feature version. Not all plug-ins have to change versions while a feature version changes each time a new release of the component is made.&lt;br /&gt;
** &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: The feature deployment build will produce a &#039;&#039;P2 repository&#039;&#039; containing &#039;&#039;content.jar&#039;&#039;, &#039;&#039;artifacts.jar&#039;&#039; and two directories, &#039;&#039;features/&#039;&#039; and &#039;&#039;plugins/&#039;&#039;. The features-directory will contain the feature as JAR files which is correct when used as a P2 repository. But if you want to install your deployed features into the current target platforms, the feature jars must be unpacked with the JAR file names as the directory names&#039; &#039;&#039;&#039;Don&#039;t unpack directly into the features directory&#039;&#039;&#039;, the feature JARs do not contain a common parent folder. For example, if you&#039;ve built your feature with an ID &#039;&#039;&#039;my.feature&#039;&#039;&#039; and version &#039;&#039;&#039;1.0.0&#039;&#039;&#039;, the build will produce a file &#039;&#039;&#039;my.feature_1.0.0.jar&#039;&#039;&#039;. The contents of this jar must be unpacked into &#039;&#039;&#039;features/my.feature_1.0.0/&#039;&#039;&#039;. If you copied the JAR files into the features directory and unpack them there, &#039;&#039;&#039;do not leave the JARs in the features directory&#039;&#039;&#039;. This will also break the features.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Developer_Documents:Privacy_policy&amp;diff=1301</id>
		<title>Developer Documents:Privacy policy</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Developer_Documents:Privacy_policy&amp;diff=1301"/>
		<updated>2010-11-08T08:41:40Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All data in this wiki is public and under EPL license, unless stated otherwise in the data.&lt;br /&gt;
&lt;br /&gt;
All user account information beyond what is visible to anyone through [[Special:SpecialPages|special pages]] is private to the [https://www.simantics.org/simantics/about-simantics/thth-simantics THTH Simantics Division] and is not disclosed to division members or any other parties.&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1150</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1150"/>
		<updated>2010-10-25T10:49:35Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Example case: Product and Purchase management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eclipse will complain that AsyncPurchaseEditorFinal.java does not compile, but it does not prevent&lt;br /&gt;
starting the application. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.java and completed ontology in example.pgraph.end&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1149</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1149"/>
		<updated>2010-10-25T10:49:16Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Example case: Product and Purchase management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Eclipse will complain that AsyncPurchaseEditorFinal.java does not compile, but it does not prevent starting the application. &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.java and completed ontology in example.pgraph.end&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1148</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1148"/>
		<updated>2010-10-25T10:45:02Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Example case: Product and Purchase management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.java and completed ontology in example.pgraph.end&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1147</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1147"/>
		<updated>2010-10-25T10:44:07Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.java and completed ontology in example.pgraph.end&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1146</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1146"/>
		<updated>2010-10-25T10:43:05Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Supporting multiple items of the same product */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.java and completed ontology in example.pgraph.end&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1145</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1145"/>
		<updated>2010-10-25T10:41:52Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Supporting multiple items of the same product */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorFinal.hava&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1144</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1144"/>
		<updated>2010-10-25T10:41:27Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Adding Context Menu to Purchase Editor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle3.hava&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1143</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1143"/>
		<updated>2010-10-25T10:41:07Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Fixing the editor updates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle2.hava&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1142</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1142"/>
		<updated>2010-10-25T10:40:51Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Adding the missing information to UI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Completed code is in org.simantics.example.phases.AsyncPurchaseEditorMiddle.hava&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1141</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1141"/>
		<updated>2010-10-25T10:37:04Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Supporting multiple items of the same product */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(purchase, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product)) {&lt;br /&gt;
       double amount = graph.getRelatedValue(productPurchase, e.ProductCount);&lt;br /&gt;
       graph.claimLiteral(productPurchase, e.ProductCount, amount + 1.0);&lt;br /&gt;
       return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
 graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and increases count by one if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1140</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1140"/>
		<updated>2010-10-25T10:21:01Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Supporting multiple items of the same product */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.pgraph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXAMPLE.ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain EXAMPLE.ProductPurchase&lt;br /&gt;
    L0.HasRange L0.Double&lt;br /&gt;
&lt;br /&gt;
EXAMPLE.ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
    @L0.singleProperty EXAMPLE.ProductCount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After this clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
   graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 for (Resource productPurchase : graph.getObjects(product, l0.ConsistsOf)) {&lt;br /&gt;
    if (graph.hasStatement(productPurchase, l0.ConsistsOf, product))&lt;br /&gt;
	  return;&lt;br /&gt;
}&lt;br /&gt;
	&lt;br /&gt;
Resource productPurchase = graph.newResource();&lt;br /&gt;
graph.claim(productPurchase, l0.InstanceOf, e.ProductPurchase);&lt;br /&gt;
graph.claimLiteral(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
graph.claim(purchase, l0.ConsistsOf, productPurchase);&lt;br /&gt;
graph.claim(productPurchase, l0.ConsistsOf, product);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1139</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1139"/>
		<updated>2010-10-25T09:15:57Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Adding Context Menu to Purchase Editor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
              if(!graph.hasStatement(purchase, l0.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, l0.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1132</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1132"/>
		<updated>2010-10-22T14:12:53Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Fixing the editor updates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new Listener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1131</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1131"/>
		<updated>2010-10-22T14:12:25Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Fixing the editor updates */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graph&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an Listener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1129</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1129"/>
		<updated>2010-10-22T12:07:43Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Deleting resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyLiteral(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyLiteral -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1128</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1128"/>
		<updated>2010-10-22T12:06:43Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Deleting resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, l0.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
                graph.denyValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyValue -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1127</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1127"/>
		<updated>2010-10-22T12:06:00Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Setting Literals */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimLiteral(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, b.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                graph.denyValue(resource, b.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyValue -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1126</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1126"/>
		<updated>2010-10-22T12:05:31Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Creating new Resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimValue(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimValue(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, l0.InstanceOf, l0.Library);&lt;br /&gt;
		graph.claimLiteral(newResource, l0.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, l0.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, b.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                graph.denyValue(resource, b.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyValue -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1125</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1125"/>
		<updated>2010-10-22T12:04:50Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Setting Literals */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			graph.claimValue(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		graph.claimValue(resource, l0.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, b.InstanceOf, b.Library);&lt;br /&gt;
		graph.claimValue(newResource, b.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, b.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, b.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                graph.denyValue(resource, b.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyValue -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
	<entry>
		<id>https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1124</id>
		<title>Tutorial: Database Development</title>
		<link rel="alternate" type="text/html" href="https://dev.simantics.org/index.php?title=Tutorial:_Database_Development&amp;diff=1124"/>
		<updated>2010-10-22T12:00:38Z</updated>

		<summary type="html">&lt;p&gt;Marko Luukkainen: /* Resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; TODO: walk through the tutorial, correct any errors found&lt;br /&gt;
&lt;br /&gt;
= Basic concepts =&lt;br /&gt;
;Session: Database session / connection that allows reading and writing the database using transactions.&lt;br /&gt;
;Transaction: A database operation; either read, or write operation. Simantics supports three types of transactions: Read, Write, and WriteOnly.&lt;br /&gt;
;Resource: A single object in the database.&lt;br /&gt;
;Statement: Triple consisting of subject, predicate, and object&lt;br /&gt;
;Literal: primitive value (int, double, String,..) or an array of primitive values.&lt;br /&gt;
&lt;br /&gt;
=Reading the database=&lt;br /&gt;
&lt;br /&gt;
==Literals==&lt;br /&gt;
&lt;br /&gt;
In this example we set a Label to show a Resource’s name. A resource&#039;s name is defined using the &#039;&#039;&#039;L0.HasName&#039;&#039;&#039; property relation.&lt;br /&gt;
&lt;br /&gt;
To support Layer0 URI &amp;amp;harr; resource mapping mechanism (see [[:Media:Layer0.pdf|Layer0.pdf]] section 4), resource names have certain restrictions.&lt;br /&gt;
* A single resource cannot have more than one statement objects with &#039;&#039;&#039;L0.ConsistsOf&#039;&#039;&#039;-predicate that have the same name. For example the following graph snippet in [[Graph File Format]] does not work with the URI &amp;amp;rarr; resource discovery mechanism:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a : L0.Entity&lt;br /&gt;
    L0.ConsistsOf&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        a : L0.Entity&lt;br /&gt;
        b : L0.Entity&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Synchronous read with a return value===&lt;br /&gt;
One way to read information stored in the database is to use synchronous reads with a return value. Return value can be any Java class, and here it is String.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	String name = session.syncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
				&lt;br /&gt;
		}});&lt;br /&gt;
	label.setText(name);&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Database connection may fail during the transaction and send an exception. Therefore you have to handle the exception in some way. Here we have wrapped the transaction inside try-catch block. In real code the most common thing to do is to let the exception propagate back to UI code.&lt;br /&gt;
&lt;br /&gt;
All literals can be read the same way, you just have to provide correct relation. There are also other methods to read literals that behave differently:&lt;br /&gt;
*getRelatedValue(): returns literal or throws and exception if value is not found&lt;br /&gt;
*getPossibleRelatedValue(): returns literal value or null, if the value does not exist.&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous read ===&lt;br /&gt;
&lt;br /&gt;
Asynchronous read allows creating requests that are processed in the background. If you don’t need the result immediately, it is recommended to use asynchronous reads for performance reasons or to prevent blocking UI threads.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new ReadRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void run(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		final String name =  graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we use separate Runnable to set the label’s text (SWT components must be accessed from main / SWT thread). Note that we have to check if the label is disposed before setting the text.&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a Procedure===&lt;br /&gt;
Using a procedure allows you to handle possible exceptions caused by failed asynchronous transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new Procedure&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(Throwable t) {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(final String name) {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Asynchronous read with a SyncListener===&lt;br /&gt;
Using &amp;lt;code&amp;gt;SyncListener&amp;lt;/code&amp;gt; with a read transaction leaves a listener to the database that notifies changes in the read data. There exist also &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AsyncListener&amp;lt;/code&amp;gt; interfaces. SyncListener provides a &#039;&#039;ReadGraph&#039;&#039; for the listener, AsyncListener provides &#039;&#039;AsyncReadGraph&#039;&#039; for the user. Using &amp;lt;code&amp;gt;Listener&amp;lt;/code&amp;gt; provides no graph access at all, just a notification of a changed read request result.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public String perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getRelatedValue(resource, l0.HasName);&lt;br /&gt;
	}&lt;br /&gt;
}, new SyncListener&amp;lt;String&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(ReadGraph graph, final String name) throws DatabaseException {&lt;br /&gt;
		Display.getDefault().asyncExec(new Runnable() {&lt;br /&gt;
			@Override&lt;br /&gt;
			public void run() {&lt;br /&gt;
				if (!label.isDisposed())&lt;br /&gt;
					label.setText(name);&lt;br /&gt;
			}&lt;br /&gt;
		});&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		return label.isDisposed();&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here the listener updates the label when the name changes. The method isDisposed() controls lifecycle of the listener, and here when the label is disposed, the listener is released and it stops updating the label.&lt;br /&gt;
&lt;br /&gt;
==Resources==&lt;br /&gt;
Reading resources is similar to reading literals. Here is an example that reads all resources that are connected to a Resource with a ConsistsOf-relation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	Collection&amp;lt;Resource&amp;gt; children = session.syncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
			Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
			return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// handle exception here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same asynchronous, Procedure, and Listener mechanisms work with reading resources. For example, you can use listener to be notified if resources are added or removed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new Read&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public Collection&amp;lt;Resource&amp;gt; perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
		Layer0 l0 = Layer0.getInstance(graph);&lt;br /&gt;
		return graph.getObjects(resource, l0.ConsistsOf);&lt;br /&gt;
	}&lt;br /&gt;
},new AsyncListener&amp;lt;Collection&amp;lt;Resource&amp;gt;&amp;gt;() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void exception(AsyncReadGraph graph, Throwable throwable){&lt;br /&gt;
		// handle exception here&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public void execute(AsyncReadGraph graph, Collection&amp;lt;Resource&amp;gt; result) {&lt;br /&gt;
		// this is run every time a resource is added or removed&lt;br /&gt;
	}&lt;br /&gt;
			&lt;br /&gt;
	@Override&lt;br /&gt;
	public boolean isDisposed() {&lt;br /&gt;
		// this must return true when the listener is not needed&lt;br /&gt;
		// anymore to release the listener&lt;br /&gt;
		return false;&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Writing the database=&lt;br /&gt;
==Setting Literals==&lt;br /&gt;
&lt;br /&gt;
Here we set a name of a resource to “New name”. Both synchronous and asynchronous versions are similar, the only difference is that with synchronous way you have to handle the exception, while using an asynchronous write without a Procedure does not let you know if the transaction failed. Any exceptions will just be logged by the database client library.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
try {&lt;br /&gt;
	session.syncRequest(new WriteRequest() {&lt;br /&gt;
		@Override&lt;br /&gt;
		public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
			Builtins b = graph.getBuiltins();&lt;br /&gt;
			graph.claimValue(resource, b.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	});&lt;br /&gt;
} catch (DatabaseException e) {&lt;br /&gt;
	// TODO Auto-generated catch block&lt;br /&gt;
	e.printStackTrace();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {	&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
		graph.claimValue(resource, b.HasName, &amp;quot;New name&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Using a Procedure with an asynchronous write transaction is similar to read transactions, so we don’t have separate example of that. Note that listeners can only be used with read transactions, not write transactions.&lt;br /&gt;
===Creating new Resources===&lt;br /&gt;
Same synchronous and asynchronous mechanisms apply to writing new Resources. The difference is that with asynchronous you can use a Callback to check if write failed, or separate WriteResult and a Procedure to return and check custom results of a write transaction.&lt;br /&gt;
&lt;br /&gt;
Here is an example that creates a new library, gives it a name “New Library” and connects it to given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
		Resource newResource = graph.newResource();&lt;br /&gt;
		graph.claim(newResource, b.InstanceOf, b.Library);&lt;br /&gt;
		graph.claimValue(newResource, b.HasName, &amp;quot;New Library&amp;quot;);&lt;br /&gt;
		graph.claim(resource, b.ConsistsOf, newResource);&lt;br /&gt;
				&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The key points here are:&lt;br /&gt;
*New resource are created with WriteGraph.newResource()&lt;br /&gt;
*You must set resource’s type using InstanceOf-relation.&lt;br /&gt;
*If you do not connect created resources anywhere, the resources become orphan resources. For orphan resources there is no statement path to/from the database root resource. They cannot be traversed and therefore found from the database.&lt;br /&gt;
&lt;br /&gt;
===Deleting resources===&lt;br /&gt;
Here is an example that removes everything the given resource consists of directly. In the end it removes all the statements from the given resource, thereby essentially removing the resource itself. A resource is considered to not exist if it has no statements, since there&#039;s nothing to define its nature.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                for (Resource consistsOf : graph.getObjects(resource, b.ConsistsOf)) {&lt;br /&gt;
                    // Remove all statements (consistsOf, ?p, ?o) and their possible inverse statements&lt;br /&gt;
                    graph.deny(consistsOf);&lt;br /&gt;
                }&lt;br /&gt;
                // Remove resource itself by removing any statements to/from it.&lt;br /&gt;
                graph.deny(resource);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Another example, that deletes the name of the given resource.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
session.asyncRequest(new WriteRequest() {&lt;br /&gt;
	@Override&lt;br /&gt;
	public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
		Builtins b = graph.getBuiltins();&lt;br /&gt;
                graph.denyValue(resource, b.HasName);&lt;br /&gt;
	}&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The key points here are:&lt;br /&gt;
*deny -methods are used to delete statements from the database&lt;br /&gt;
*denyValue -methods are used to delete literal values from the database&lt;br /&gt;
*A resource that has no statements does not exist.&lt;br /&gt;
&lt;br /&gt;
=Example case: Product and Purchase management=&lt;br /&gt;
&lt;br /&gt;
In this example, we will implement a simple product and purchase management system. The system will allow user to define new products, and create new purchase orders. To keep the example simple, the products have just a name and unit cost, and purchase orders will have name of the customer and a list of ordered products.&lt;br /&gt;
&lt;br /&gt;
We have already implemented skeleton for the system. It contains basic user interface for creating products and purchases, but it lacks several features that we are going to add during this tutorial. The base code can be found from SVN:&lt;br /&gt;
&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example&lt;br /&gt;
*https://www.simulationsite.net/svn/simantics/tutorials/trunk/org.simantics.example.feature&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre style=&amp;quot;white-space: pre-wrap&amp;quot;&amp;gt;&lt;br /&gt;
TODO : while the tutorial code exists, currently SVN contains version that is the result of this tutorial.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ontology that we are using is defined in &#039;&#039;Example.pgraph&#039;&#039; file. It is in &#039;&#039;org.simantics.example/graphs&#039;&#039; folder. To run the example application, use &#039;&#039;simantics-example.product&#039;&#039;. After starting the example product, you should get a user interface like the one in Figure 1.&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial_start.png|thumb|600px|center|Figure 1: Tutorial application after one created product (Product 1) and one purchase.]]&lt;br /&gt;
&lt;br /&gt;
When you use the application you may notice following:&lt;br /&gt;
*Name of the customer or the date of the order is not shown anywhere.&lt;br /&gt;
*When purchase editor is open, new products won’t show up in it. Only closing and opening the editor shows the products.&lt;br /&gt;
*Adding new products to purchases can be done only in Example Browser&lt;br /&gt;
*While you can order several products, you cannot order multiple items of the same product.&lt;br /&gt;
&lt;br /&gt;
Org.simantics.example plug-in is split into four packages:&lt;br /&gt;
*editors: Purchase Editor implementation.&lt;br /&gt;
*handlers: UI actions.&lt;br /&gt;
*project: Project binding. See … for more details.&lt;br /&gt;
*resource:  Taxonomy generated from the used ontology.&lt;br /&gt;
&lt;br /&gt;
The most important parts of this tutorial are editors. AsyncPurchaseEditor and classes in handlers-package.&lt;br /&gt;
&lt;br /&gt;
==Adding the missing information to UI==&lt;br /&gt;
First we have to add new Text widgets to the Purchase Editor. At the beginning of AsyncPurchaseEditor.java you see:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// UI controls&lt;br /&gt;
private final Text totalCost;&lt;br /&gt;
private final TableViewer productViewer;&lt;br /&gt;
private final TableViewerColumn nameColumn;&lt;br /&gt;
private final TableViewerColumn costColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add new line after totalCost:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final Text customer;&lt;br /&gt;
private final Text date;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then we have to instantiate text fields, create labels that inform user what the text fields mean, and setup the layout properly. In the beginning of the constructor modify:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Label l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Customer:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
        &lt;br /&gt;
customer = new Text(this, SWT.NONE);&lt;br /&gt;
customer.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(customer);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Date:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
date = new Text(this, SWT.NONE);&lt;br /&gt;
date.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(date);&lt;br /&gt;
&lt;br /&gt;
l = new Label(this, SWT.NONE);&lt;br /&gt;
l.setText(&amp;quot;Total Price:&amp;quot;);&lt;br /&gt;
GridDataFactory.fillDefaults().applyTo(l);&lt;br /&gt;
&lt;br /&gt;
totalCost = new Text(this, SWT.NONE);&lt;br /&gt;
totalCost.setEditable(false);&lt;br /&gt;
GridDataFactory.fillDefaults().grab(true, false).applyTo(totalCost);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And finally, we have to update text fields to show the data. Modify updateUI(Model m) method to contain:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
customer.setText(m.boughtBy);&lt;br /&gt;
date.setText(m.boughtAt);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Fixing the editor updates==&lt;br /&gt;
Currently the Purchase Editor loads products in the purchase when the editor is opened, but if new products are added, editor’s user interface won’t update. To fix this, modify AsyncPurhaseEditor’s setInput(Resource) method. Currently the method is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
    this.input = r;&lt;br /&gt;
    if (input == null)&lt;br /&gt;
        return;&lt;br /&gt;
&lt;br /&gt;
    session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
       @Override&lt;br /&gt;
       public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
           return loadModel(graph, input);&lt;br /&gt;
       }&lt;br /&gt;
    }, new Procedure&amp;lt;Model&amp;gt;() {&lt;br /&gt;
          @Override&lt;br /&gt;
          public void exception(Throwable throwable) {&lt;br /&gt;
                ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
          }&lt;br /&gt;
          @Override&lt;br /&gt;
          public void execute(final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
         }&lt;br /&gt;
   });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hint: You have to replace the Procedure with an AsyncListener.&lt;br /&gt;
&lt;br /&gt;
Answer:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void setInput(Resource r) {&lt;br /&gt;
   this.input = r;&lt;br /&gt;
   if (input == null)&lt;br /&gt;
      return;&lt;br /&gt;
&lt;br /&gt;
   session.asyncRequest(new Read&amp;lt;Model&amp;gt;() {&lt;br /&gt;
      @Override&lt;br /&gt;
      public Model perform(ReadGraph graph) throws DatabaseException {&lt;br /&gt;
         return loadModel(graph, input);&lt;br /&gt;
      }&lt;br /&gt;
   }, new AsyncListener&amp;lt;Model&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public boolean isDisposed() {&lt;br /&gt;
        	return AsyncPurchaseEditor.this.isDisposed();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        @Override&lt;br /&gt;
        public void exception(AsyncReadGraph graph, Throwable throwable) {&lt;br /&gt;
        	ExceptionUtils.logAndShowError(throwable);&lt;br /&gt;
        }&lt;br /&gt;
            &lt;br /&gt;
        @Override&lt;br /&gt;
        public void execute(AsyncReadGraph graph, final Model result) {&lt;br /&gt;
            // Set the loaded model as the model viewed by the UI.&lt;br /&gt;
            getDisplay().asyncExec(new Runnable() {&lt;br /&gt;
               @Override&lt;br /&gt;
               public void run() {&lt;br /&gt;
                  if (AsyncPurchaseEditor.this.isDisposed())&lt;br /&gt;
                     return;&lt;br /&gt;
                  updateUI(result);&lt;br /&gt;
               }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this modification the editor should update its contents when the data is changed. You may try to add new product to purchase order when the editor is open to check that it really works.&lt;br /&gt;
&lt;br /&gt;
==Adding Context Menu to Purchase Editor==&lt;br /&gt;
We are going to add context menu to Purchase editor. The context menu will be used for adding new products to a purchase.&lt;br /&gt;
&lt;br /&gt;
There are several ways to implement the context menu in Eclipse. For sake of simplicity, we are not going to implement context menu that allows contributions from plug-in definitions (plugin.xml). &lt;br /&gt;
&lt;br /&gt;
The code that Example Browser uses in its menu is in handlers.AddProductsContributionItem. Sadly, we cannot reuse that implementation, since it uses Eclipse’s selection mechanism to interpret current purchase, while we want to use the purchase that editor has opened.&lt;br /&gt;
&lt;br /&gt;
Put this class to AsyncPurchaseEditor.java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public class AddProductsContributionItem extends CompoundContributionItem {&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem() {&lt;br /&gt;
    super();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public AddProductsContributionItem(String id) {&lt;br /&gt;
    super(id);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  @Override&lt;br /&gt;
  protected IContributionItem[] getContributionItems() {&lt;br /&gt;
&lt;br /&gt;
    ProductManagerImpl manager = SimanticsUI.getProject().getHint(ProductManager.PRODUCT_MANAGER);&lt;br /&gt;
&lt;br /&gt;
    Map&amp;lt;Resource, String&amp;gt; products = manager.getProducts();&lt;br /&gt;
&lt;br /&gt;
    final Resource purchase = input;&lt;br /&gt;
            &lt;br /&gt;
    IContributionItem[] result = new IContributionItem[products.size()];&lt;br /&gt;
    int i=0;&lt;br /&gt;
    System.out.println(&amp;quot;Products count = &amp;quot; + products.size());&lt;br /&gt;
    for(Map.Entry&amp;lt;Resource, String&amp;gt; entry : products.entrySet()) {&lt;br /&gt;
      final Resource product = entry.getKey();&lt;br /&gt;
      result[i++] = new ActionContributionItem(new Action(&amp;quot;Add &amp;quot; + entry.getValue()) {&lt;br /&gt;
        @Override&lt;br /&gt;
        public void run() {&lt;br /&gt;
          SimanticsUI.getSession().asyncRequest(new WriteRequest() {&lt;br /&gt;
            @Override&lt;br /&gt;
            public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
              Builtins b = graph.getBuiltins();&lt;br /&gt;
              if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
                graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
              }&lt;br /&gt;
           });&lt;br /&gt;
         }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
    return result;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
It is the same code as handlers.AddProductsContributionItem, but the selection mechanism has been replaced with the editor input.&lt;br /&gt;
&lt;br /&gt;
To add context menu to the editor, add this code to the end of AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
final MenuManager manager = new MenuManager();&lt;br /&gt;
manager.add(new AddProductsContributionItem());&lt;br /&gt;
Menu menu = manager.createContextMenu(productViewer.getControl());&lt;br /&gt;
&lt;br /&gt;
this.addDisposeListener(new DisposeListener() {&lt;br /&gt;
			&lt;br /&gt;
    @Override&lt;br /&gt;
    public void widgetDisposed(DisposeEvent e) {&lt;br /&gt;
	manager.dispose();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
        &lt;br /&gt;
productViewer.getControl().setMenu(menu);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Supporting multiple items of the same product==&lt;br /&gt;
Current ontology is designed so that one purchase order contains products, but product count cannot be stored anywhere [Figure 2].&lt;br /&gt;
&lt;br /&gt;
[[Image:simantics_db_tutorial1.png|thumb|center|700px|Figure 2: Purchases contain only links to products, and there is no way to store product count.]]&lt;br /&gt;
&lt;br /&gt;
To add support for product count we have to change the ontology. We have to introduce new type “ProductPurchase” that will have link to ordered Product and property for product count [Figure 3]. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial2.png|thumb|center|700px|Figure 3: Purchases contain ProductCounts that link to Products.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Open the ontology (example.graph) and add these to ExampleOntology:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ProductCount &amp;lt;R L0.HasProperty : L0.FunctionalRelation&lt;br /&gt;
    L0.HasDomain [ProductPurchase]&lt;br /&gt;
    L0.HasRange [L0.Double]&lt;br /&gt;
            &lt;br /&gt;
ProductPurchase &amp;lt;T L0.Entity&lt;br /&gt;
   [ProductCount card &amp;quot;1&amp;quot;]&lt;br /&gt;
   [L0.ConsistsOf all Product]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Also replace Purchase definition with: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Purchase &amp;lt;T L0.Entity&lt;br /&gt;
    [BoughtBy card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [BoughtAt card &amp;quot;1&amp;quot;]&lt;br /&gt;
    [L0.ConsistsOf all ProductPurchase]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After this generate the database (run generate_tutorials.bat) and refresh your workspace (Eclipse caches files, and does not automatically detect if files have been changed). You must also remember to clean the applications workspace, since now it has a database with old ontologies.&lt;br /&gt;
 &lt;br /&gt;
To get the application working, we must update AddProductContributionsItem.java and AsyncPurchaseEditor.java. We start with the AddProduct…java. Currently its wrote transaction is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   if(!graph.hasStatement(purchase, b.ConsistsOf, product))&lt;br /&gt;
      graph.claim(purchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This just creates a link between the Purchase and selected Product. We need to create an instance of ProductPurchase link it to the Purchase and to selected Product:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
public void perform(WriteGraph graph) throws DatabaseException {&lt;br /&gt;
   Builtins b = graph.getBuiltins();&lt;br /&gt;
   ExampleResource e = ExampleResource.getInstance(graph);&lt;br /&gt;
                            &lt;br /&gt;
   for (Resource productPurchase : graph.getObjects(product, b.ConsistsOf)) {&lt;br /&gt;
      if (graph.hasStatement(productPurchase, b.ConsistsOf, product))&lt;br /&gt;
           return;&lt;br /&gt;
      }&lt;br /&gt;
                            &lt;br /&gt;
    Resource productPurchase = graph.newResource();&lt;br /&gt;
    graph.claim(productPurchase, b.InstanceOf, e.ProductPurchase);&lt;br /&gt;
    graph.claimValue(productPurchase, e.ProductCount, 1.0);&lt;br /&gt;
    graph.claim(purchase, b.ConsistsOf, productPurchase);&lt;br /&gt;
    graph.claim(productPurchase, b.ConsistsOf, product);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This code checks first if the product is already in the purchase, and does not do anything if it is.&lt;br /&gt;
&lt;br /&gt;
Then we edit AsyncPurchaseEditor.java.  Start by adding “amount” to Item:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Item {&lt;br /&gt;
   String name;&lt;br /&gt;
   double costs;&lt;br /&gt;
   double amount;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Next, change loadModel() method to read the data in current form and include product count:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (g.isInstanceOf(modelResource, ex.Purchase)) {&lt;br /&gt;
   Resource purchase = modelResource;&lt;br /&gt;
   m.boughtAt = g.getRelatedValue(purchase, ex.BoughtAt);&lt;br /&gt;
   m.boughtBy = g.getRelatedValue(purchase, ex.BoughtBy);&lt;br /&gt;
&lt;br /&gt;
   List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;Item&amp;gt;();&lt;br /&gt;
   for (Resource productPurchase : g.getObjects(purchase, g.getBuiltins().ConsistsOf)) {&lt;br /&gt;
     	Resource product = g.getSingleObject(productPurchase, b.ConsistsOf);&lt;br /&gt;
      Item i = new Item();&lt;br /&gt;
      i.name = g.getRelatedValue(product, b.HasName);&lt;br /&gt;
      i.costs = g.getRelatedValue(product, ex.Costs);&lt;br /&gt;
      i.amount = g.getRelatedValue(productPurchase, ex.ProductCount);&lt;br /&gt;
      items.add(i);&lt;br /&gt;
   }&lt;br /&gt;
   m.items = items.toArray(new Item[items.size()]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then update AddProductContributionItem inside AsyncPurchaseEditor.java to match the previous edit.&lt;br /&gt;
&lt;br /&gt;
To show the product count we have to add new column to the table. First, create a member for the column:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private final TableViewerColumn amountColumn;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then initialize the column in the AsyncPurchaseEditor’s constructor:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
amountColumn = new TableViewerColumn(productViewer, SWT.LEFT);&lt;br /&gt;
amountColumn.getColumn().setWidth(100);&lt;br /&gt;
amountColumn.getColumn().setText(&amp;quot;Amount&amp;quot;);&lt;br /&gt;
amountColumn.setLabelProvider(new CellLabelProvider() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public void update(ViewerCell cell) {&lt;br /&gt;
        Item i = (Item) cell.getElement();&lt;br /&gt;
        cell.setText(String.valueOf(i.amount));&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And last, change updateUI() method to calculate total costs correctly and update the table’s layout:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
private void updateUI(Model m) {&lt;br /&gt;
   // Update the UI based on the contents of the specified model.&lt;br /&gt;
   double total = 0;&lt;br /&gt;
   for (Item i : m.items) {&lt;br /&gt;
      total += i.costs * i.amount;&lt;br /&gt;
   }&lt;br /&gt;
   totalCost.setText(String.valueOf(total));&lt;br /&gt;
&lt;br /&gt;
   customer.setText(m.boughtBy);&lt;br /&gt;
   date.setText(m.boughtAt);&lt;br /&gt;
        &lt;br /&gt;
   productViewer.setInput(m);&lt;br /&gt;
&lt;br /&gt;
   nameColumn.getColumn().pack();&lt;br /&gt;
   costColumn.getColumn().pack();&lt;br /&gt;
   amountColumn.getColumn().pack();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
After these modifications, your application should look like in Figure 4.&lt;br /&gt;
&lt;br /&gt;
[[File:simantics_db_tutorial_amount.png|thumb|center|700px|Figure 4: Amount column has been added into the table.]]&lt;/div&gt;</summary>
		<author><name>Marko Luukkainen</name></author>
	</entry>
</feed>