Initial contribution for BTF -> ATDB importer.

Change-Id: I98aeee27645121e7df2fd076cd96a90e90ddc535
Signed-off-by: Raphael Weber <raphael.weber@vector.com>
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/.classpath b/plugins/org.eclipse.app4mc.amalthea.import.btf/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/.project b/plugins/org.eclipse.app4mc.amalthea.import.btf/.project
new file mode 100644
index 0000000..929f69b
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.app4mc.amalthea.import.btf</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.core.resources.prefs b/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0c68a61
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/META-INF/MANIFEST.MF b/plugins/org.eclipse.app4mc.amalthea.import.btf/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..fdbf5a2
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: APP4MC Amalthea BTF to ATDB import
+Bundle-SymbolicName: org.eclipse.app4mc.amalthea.import.btf;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Require-Bundle: org.sqlite.jdbc,
+ org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.ui.ide,
+ org.eclipse.core.resources,
+ org.eclipse.app4mc.amalthea.model
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Bundle-Vendor: Eclipse APP4MC
+Automatic-Module-Name: org.eclipse.app4mc.amalthea.import.btf
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/about.html b/plugins/org.eclipse.app4mc.amalthea.import.btf/about.html
new file mode 100644
index 0000000..164f781
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>About</title>
+</head>
+<body lang="EN-US">
+	<h2>About This Content</h2>
+
+	<p>November 30, 2017</p>
+	<h3>License</h3>
+
+	<p>
+		The Eclipse Foundation makes available all content in this plug-in
+		(&quot;Content&quot;). Unless otherwise indicated below, the Content
+		is provided to you under the terms and conditions of the Eclipse
+		Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
+		available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		For purposes of the EPL, &quot;Program&quot; will mean the Content.
+	</p>
+
+	<p>
+		If you did not receive this Content directly from the Eclipse
+		Foundation, the Content is being redistributed by another party
+		(&quot;Redistributor&quot;) and different terms and conditions may
+		apply to your use of any object code in the Content. Check the
+		Redistributor's license that was provided with the Content. If no such
+		license exists, contact the Redistributor. Unless otherwise indicated
+		below, the terms and conditions of the EPL still apply to any source
+		code in the Content and such source code may be obtained at <a
+			href="http://www.eclipse.org/">http://www.eclipse.org</a>.
+	</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/build.properties b/plugins/org.eclipse.app4mc.amalthea.import.btf/build.properties
new file mode 100644
index 0000000..0d3d3a7
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+               META-INF/,\
+               .,\
+               icons/
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/epl-2.0.html b/plugins/org.eclipse.app4mc.amalthea.import.btf/epl-2.0.html
new file mode 100644
index 0000000..637a181
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/epl-2.0.html
@@ -0,0 +1,300 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title>Eclipse Public License - Version 2.0</title>
+    <style type="text/css">
+      body {
+        margin: 1.5em 3em;
+      }
+      h1{
+        font-size:1.5em;
+      }
+      h2{
+        font-size:1em;
+        margin-bottom:0.5em;
+        margin-top:1em;
+      }
+      p {
+        margin-top:  0.5em;
+        margin-bottom: 0.5em;
+      }
+      ul, ol{
+        list-style-type:none;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Eclipse Public License - v 2.0</h1>
+    <p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+      PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION
+      OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.
+    </p>
+    <h2 id="definitions">1. DEFINITIONS</h2>
+    <p>&ldquo;Contribution&rdquo; means:</p>
+    <ul>
+      <li>a) in the case of the initial Contributor, the initial content
+        Distributed under this Agreement, and
+      </li>
+      <li>
+        b) in the case of each subsequent Contributor:
+        <ul>
+          <li>i) changes to the Program, and</li>
+          <li>ii) additions to the Program;</li>
+        </ul>
+        where such changes and/or additions to the Program originate from
+        and are Distributed by that particular Contributor. A Contribution
+        &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such
+        Contributor itself or anyone acting on such Contributor&#039;s behalf.
+        Contributions do not include changes or additions to the Program that
+        are not Modified Works.
+      </li>
+    </ul>
+    <p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>
+    <p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which
+      are necessarily infringed by the use or sale of its Contribution alone
+      or when combined with the Program.
+    </p>
+    <p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this
+      Agreement.
+    </p>
+    <p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement
+      or any Secondary License (as applicable), including Contributors.
+    </p>
+    <p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other
+      form, that is based on (or derived from) the Program and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship.
+    </p>
+    <p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that
+      results from an addition to, deletion from, or modification of the
+      contents of the Program, including, for purposes of clarity any new file
+      in Source Code form that contains any contents of the Program. Modified
+      Works shall not include works that contain only declarations, interfaces,
+      types, classes, structures, or files of the Program solely in each case
+      in order to link to, bind by name, or subclass the Program or Modified
+      Works thereof.
+    </p>
+    <p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available
+      in any manner that enables the transfer of a copy.
+    </p>
+    <p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making
+      modifications, including but not limited to software source code,
+      documentation source, and configuration files.
+    </p>
+    <p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,
+      Version 2.0, or any later versions of that license, including any
+      exceptions or additional permissions as identified by the initial
+      Contributor.
+    </p>
+    <h2 id="grant-of-rights">2. GRANT OF RIGHTS</h2>
+    <ul>
+      <li>a) Subject to the terms of this Agreement, each Contributor hereby
+        grants Recipient a non-exclusive, worldwide, royalty-free copyright
+        license to reproduce, prepare Derivative Works of, publicly display,
+        publicly perform, Distribute and sublicense the Contribution of such
+        Contributor, if any, and such Derivative Works.
+      </li>
+      <li>b) Subject to the terms of this Agreement, each Contributor hereby
+        grants Recipient a non-exclusive, worldwide, royalty-free patent
+        license under Licensed Patents to make, use, sell, offer to sell,
+        import and otherwise transfer the Contribution of such Contributor,
+        if any, in Source Code or other form. This patent license shall
+        apply to the combination of the Contribution and the Program if,
+        at the time the Contribution is added by the Contributor, such
+        addition of the Contribution causes such combination to be covered
+        by the Licensed Patents. The patent license shall not apply to any
+        other combinations which include the Contribution. No hardware per
+        se is licensed hereunder.
+      </li>
+      <li>c) Recipient understands that although each Contributor grants the
+        licenses to its Contributions set forth herein, no assurances are
+        provided by any Contributor that the Program does not infringe the
+        patent or other intellectual property rights of any other entity.
+        Each Contributor disclaims any liability to Recipient for claims
+        brought by any other entity based on infringement of intellectual
+        property rights or otherwise. As a condition to exercising the rights
+        and licenses granted hereunder, each Recipient hereby assumes sole
+        responsibility to secure any other intellectual property rights needed,
+        if any. For example, if a third party patent license is required to
+        allow Recipient to Distribute the Program, it is Recipient&#039;s
+        responsibility to acquire that license before distributing the Program.
+      </li>
+      <li>d) Each Contributor represents that to its knowledge it has sufficient
+        copyright rights in its Contribution, if any, to grant the copyright
+        license set forth in this Agreement.
+      </li>
+      <li>e) Notwithstanding the terms of any Secondary License, no Contributor
+        makes additional grants to any Recipient (other than those set forth
+        in this Agreement) as a result of such Recipient&#039;s receipt of the
+        Program under the terms of a Secondary License (if permitted under
+        the terms of Section 3).
+      </li>
+    </ul>
+    <h2 id="requirements">3. REQUIREMENTS</h2>
+    <p>3.1 If a Contributor Distributes the Program in any form, then:</p>
+    <ul>
+      <li>a) the Program must also be made available as Source Code, in
+        accordance with section 3.2, and the Contributor must accompany
+        the Program with a statement that the Source Code for the Program
+        is available under this Agreement, and informs Recipients how to
+        obtain it in a reasonable manner on or through a medium customarily
+        used for software exchange; and
+      </li>
+      <li>
+        b) the Contributor may Distribute the Program under a license
+        different than this Agreement, provided that such license:
+        <ul>
+          <li>i) effectively disclaims on behalf of all other Contributors all
+            warranties and conditions, express and implied, including warranties
+            or conditions of title and non-infringement, and implied warranties
+            or conditions of merchantability and fitness for a particular purpose;
+          </li>
+          <li>ii) effectively excludes on behalf of all other Contributors all
+            liability for damages, including direct, indirect, special, incidental
+            and consequential damages, such as lost profits;
+          </li>
+          <li>iii) does not attempt to limit or alter the recipients&#039; rights in the
+            Source Code under section 3.2; and
+          </li>
+          <li>iv) requires any subsequent distribution of the Program by any party
+            to be under a license that satisfies the requirements of this section 3.
+          </li>
+        </ul>
+      </li>
+    </ul>
+    <p>3.2 When the Program is Distributed as Source Code:</p>
+    <ul>
+      <li>a) it must be made available under this Agreement, or if the Program (i)
+        is combined with other material in a separate file or files made available
+        under a Secondary License, and (ii) the initial Contributor attached to
+        the Source Code the notice described in Exhibit A of this Agreement,
+        then the Program may be made available under the terms of such
+        Secondary Licenses, and
+      </li>
+      <li>b) a copy of this Agreement must be included with each copy of the Program.</li>
+    </ul>
+    <p>3.3 Contributors may not remove or alter any copyright, patent, trademark,
+      attribution notices, disclaimers of warranty, or limitations of liability
+      (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which
+      they Distribute, provided that Contributors may add their own appropriate
+      notices.
+    </p>
+    <h2 id="commercial-distribution">4. COMMERCIAL DISTRIBUTION</h2>
+    <p>Commercial distributors of software may accept certain responsibilities
+      with respect to end users, business partners and the like. While this
+      license is intended to facilitate the commercial use of the Program, the
+      Contributor who includes the Program in a commercial product offering should
+      do so in a manner which does not create potential liability for other
+      Contributors. Therefore, if a Contributor includes the Program in a
+      commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)
+      hereby agrees to defend and indemnify every other Contributor
+      (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs
+      (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions
+      brought by a third party against the Indemnified Contributor to the extent
+      caused by the acts or omissions of such Commercial Contributor in connection
+      with its distribution of the Program in a commercial product offering.
+      The obligations in this section do not apply to any claims or Losses relating
+      to any actual or alleged intellectual property infringement. In order to
+      qualify, an Indemnified Contributor must: a) promptly notify the
+      Commercial Contributor in writing of such claim, and b) allow the Commercial
+      Contributor to control, and cooperate with the Commercial Contributor in,
+      the defense and any related settlement negotiations. The Indemnified
+      Contributor may participate in any such claim at its own expense.
+    </p>
+    <p>For example, a Contributor might include the Program
+      in a commercial product offering, Product X. That Contributor is then a
+      Commercial Contributor. If that Commercial Contributor then makes performance
+      claims, or offers warranties related to Product X, those performance claims
+      and warranties are such Commercial Contributor&#039;s responsibility alone.
+      Under this section, the Commercial Contributor would have to defend claims
+      against the other Contributors related to those performance claims and
+      warranties, and if a court requires any other Contributor to pay any damages
+      as a result, the Commercial Contributor must pay those damages.
+    </p>
+    <h2 id="warranty">5. NO WARRANTY</h2>
+    <p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
+      BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT
+      WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
+      WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+      MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+      solely responsible for determining the appropriateness of using and
+      distributing the Program and assumes all risks associated with its
+      exercise of rights under this Agreement, including but not limited to the
+      risks and costs of program errors, compliance with applicable laws, damage
+      to or loss of data, programs or equipment, and unavailability or
+      interruption of operations.
+    </p>
+    <h2 id="disclaimer">6. DISCLAIMER OF LIABILITY</h2>
+    <p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
+      BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY
+      LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+      OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),
+      HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+      LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+      OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+      GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+    </p>
+    <h2 id="general">7. GENERAL</h2>
+    <p>If any provision of this Agreement is invalid or unenforceable under
+      applicable law, it shall not affect the validity or enforceability of the
+      remainder of the terms of this Agreement, and without further action by the
+      parties hereto, such provision shall be reformed to the minimum extent
+      necessary to make such provision valid and enforceable.
+    </p>
+    <p>If Recipient institutes patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+      (excluding combinations of the Program with other software or hardware)
+      infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted
+      under Section 2(b) shall terminate as of the date such litigation is filed.
+    </p>
+    <p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to
+      comply with any of the material terms or conditions of this Agreement and
+      does not cure such failure in a reasonable period of time after becoming
+      aware of such noncompliance. If all Recipient&#039;s rights under this Agreement
+      terminate, Recipient agrees to cease use and distribution of the Program
+      as soon as reasonably practicable. However, Recipient&#039;s obligations under
+      this Agreement and any licenses granted by Recipient relating to the
+      Program shall continue and survive.
+    </p>
+    <p>Everyone is permitted to copy and distribute copies of this Agreement,
+      but in order to avoid inconsistency the Agreement is copyrighted and may
+      only be modified in the following manner. The Agreement Steward reserves
+      the right to publish new versions (including revisions) of this Agreement
+      from time to time. No one other than the Agreement Steward has the right
+      to modify this Agreement. The Eclipse Foundation is the initial Agreement
+      Steward. The Eclipse Foundation may assign the responsibility to serve as
+      the Agreement Steward to a suitable separate entity. Each new version of
+      the Agreement will be given a distinguishing version number. The Program
+      (including Contributions) may always be Distributed subject to the version
+      of the Agreement under which it was received. In addition, after a new
+      version of the Agreement is published, Contributor may elect to Distribute
+      the Program (including its Contributions) under the new version.
+    </p>
+    <p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+      receives no rights or licenses to the intellectual property of any
+      Contributor under this Agreement, whether expressly, by implication,
+      estoppel or otherwise. All rights in the Program not expressly granted
+      under this Agreement are reserved. Nothing in this Agreement is intended
+      to be enforceable by any entity that is not a Contributor or Recipient.
+      No third-party beneficiary rights are created under this Agreement.
+    </p>
+    <h2 id="exhibit-a">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>
+    <p>&ldquo;This Source Code may also be made available under the following 
+    	Secondary Licenses when the conditions for such availability set forth 
+    	in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+    	version(s), and exceptions or additional permissions here}.&rdquo;
+    </p>
+    <blockquote>
+      <p>Simply including a copy of this Agreement, including this Exhibit A
+        is not sufficient to license the Source Code under Secondary Licenses.
+      </p>
+      <p>If it is not possible or desirable to put the notice in a particular file,
+        then You may include the notice in a location (such as a LICENSE file in a
+        relevant directory) where a recipient would be likely to look for
+        such a notice.
+      </p>
+      <p>You may add additional accurate notices of copyright ownership.</p>
+    </blockquote>
+  </body>
+</html>
\ No newline at end of file
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/icons/amalthea.gif b/plugins/org.eclipse.app4mc.amalthea.import.btf/icons/amalthea.gif
new file mode 100644
index 0000000..f7e26f4
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/icons/amalthea.gif
Binary files differ
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/plugin.xml b/plugins/org.eclipse.app4mc.amalthea.import.btf/plugin.xml
new file mode 100644
index 0000000..86812a5
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/plugin.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+   <extension point="org.eclipse.ui.importWizards">
+      <wizard
+            category="org.eclipse.app4mc.amalthea.import.amalthea"
+            class="org.eclipse.app4mc.amalthea._import.btf.wizard.ImportWizard"
+            icon="icons/amalthea.gif"
+            id="org.eclipse.app4mc.amalthea.import.btf.wizard"
+            name="AMALTHEA Trace DB from BTF" />
+      <category id="org.eclipse.app4mc.amalthea.import.amalthea" name="AMALTHEA" />
+   </extension>
+
+</plugin>
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBBuilder.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBBuilder.java
new file mode 100644
index 0000000..bbffade
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBBuilder.java
@@ -0,0 +1,413 @@
+package org.eclipse.app4mc.amalthea._import.btf;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFEntityState;
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFEntityType;
+
+public class ATDBBuilder {
+
+	private final Connection connection;
+	private final Statement statement;
+	
+	public ATDBBuilder(final String atdbFile) throws SQLException {
+		try {
+			Class.forName("org.sqlite.JDBC"); // init JDBC driver
+		} catch (ClassNotFoundException e) {
+			// fail silently. DriverManager will throw an SQL exception complaining about a missing driver
+		}
+		this.connection = DriverManager.getConnection("jdbc:sqlite:" + atdbFile);
+		this.statement = connection.createStatement();
+		this.statement.setQueryTimeout(30); // set timeout to 30 sec.
+		this.statement.executeUpdate("PRAGMA foreign_keys = ON;"); // enable foreign key checks
+	}
+	
+	public Connection getCurrentConnection() {
+		return this.connection;
+	}
+	
+	public void closeATDB() throws SQLException {
+		this.connection.close();
+	}
+	
+	public ATDBBuilder createBasicDBStructure() throws SQLException {
+		// create meta info table
+		this.statement.executeUpdate("CREATE TABLE metaInformation (\n"
+				+ "  name  TEXT PRIMARY KEY,\n"
+				+ "  value TEXT\n"
+				+ ");");
+
+		// create entity type table and index
+		this.statement.executeUpdate("CREATE TABLE entityType (\n"
+				+ "  id   INTEGER PRIMARY KEY,\n"
+				+ "  name TEXT NOT NULL UNIQUE\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX entityTypeIndex ON entityType(name);");
+
+		// create entity table and index
+		this.statement.executeUpdate("CREATE TABLE entity (\n"
+				+ "  id           INTEGER PRIMARY KEY,\n"
+				+ "  name         TEXT NOT NULL UNIQUE,\n"
+				+ "  entityTypeId REFERENCES entityType(id)\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX entityIndex ON entity(name);");
+		
+		// create entity instance table and index
+		this.statement.executeUpdate("CREATE TABLE entityInstance (\n"
+				+ "  entityId REFERENCES entity(id),\n"
+				+ "  sqcnr    INTEGER,\n"
+				+ "  PRIMARY KEY(entityId, sqcnr)\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX entityInstanceIndex ON entityInstance(entityId, sqcnr);");
+
+		// create event type table and index
+		this.statement.executeUpdate("CREATE TABLE eventType (\n"
+				+ "  id   INTEGER PRIMARY KEY,\n"
+				+ "  name TEXT NOT NULL UNIQUE\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX eventTypeIndex ON eventType(name);");
+
+		// create property table and index
+		this.statement.executeUpdate("CREATE TABLE property (\n"
+				+ "  id   INTEGER PRIMARY KEY,\n"
+				+ "  name TEXT NOT NULL UNIQUE,\n"
+				+ "  type TEXT"//
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX propertyIndex ON property(name);");
+
+		// create property value table and index
+		this.statement.executeUpdate("CREATE TABLE propertyValue (\n"
+				+ "  entityId   REFERENCES entity(id),\n"
+				+ "  propertyId REFERENCES property(id),\n"
+				+ "  sqcnr      INTEGER DEFAULT 0,\n"
+				+ "  value      TEXT,\n"
+				+ "  PRIMARY KEY(entityId, propertyId, sqcnr)\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX propertyValueIndex ON propertyValue(entityId, propertyId);");
+		
+		// create observable event table and index
+		this.statement.executeUpdate("CREATE TABLE event (\n"
+				+ "  id             INTEGER PRIMARY KEY,\n"
+				+ "  name           TEXT NOT NULL UNIQUE,\n"
+				+ "  eventTypeId    REFERENCES eventType,\n"
+				+ "  entityId       REFERENCES entity,\n"
+				+ "  sourceEntityId REFERENCES entity DEFAULT NULL\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX eventIndex ON event(name);");
+		
+		// create metric table and index
+		this.statement.executeUpdate("CREATE TABLE metric (\n"
+				+ "  id        INTEGER PRIMARY KEY,\n"
+				+ "  name      TEXT NOT NULL UNIQUE,\n"
+				+ "  dimension TEXT NOT NULL\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE UNIQUE INDEX metricIndex ON metric(name);");
+
+		// create entity metric instance value table and index
+		this.statement.executeUpdate("CREATE TABLE entityMetricInstanceValue (\n"
+				+ "  entityId       REFERENCES entity(id),\n"
+				+ "  metricId       REFERENCES metric(id),\n"
+				+ "  sqcnr          INTEGER,\n"
+				+ "  value          TEXT,\n"
+				+ "  PRIMARY KEY(entityId, metricId, sqcnr)\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX entityMetricInstanceValueIndex ON entityMetricInstanceValue(entityId, metricId, sqcnr);");
+		
+		// create entity instance metric value table and index
+		this.statement.executeUpdate("CREATE TABLE entityInstanceMetricValue (\n"
+				+ "  entityId       ,\n"
+				+ "  entityInstance ,\n"
+				+ "  metricId       REFERENCES metric(id),\n"
+				+ "  value          TEXT,\n"
+				+ "  PRIMARY KEY(entityId, entityInstance, metricId),\n"
+				+ "  FOREIGN KEY(entityId, entityInstance) REFERENCES entityInstance\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX entityInstanceMetricValueIndex ON entityInstanceMetricValue(entityId, entityInstance, metricId);");
+		
+		// create entity metric value table and index
+		this.statement.executeUpdate("CREATE TABLE entityMetricValue (\n"
+				+ "  entityId REFERENCES entity(id),\n"
+				+ "  metricId REFERENCES metric(id),\n"
+				+ "  value    TEXT,\n"
+				+ "  PRIMARY KEY(entityId, metricId)\n"
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX entityMetricValueIndex ON entityMetricValue(entityId, metricId);");
+		
+		return this;
+	}
+	
+	public ATDBBuilder createBasicViews() throws SQLException {
+		final String idRefCase = "    WHEN %2$s.propertyId IN (SELECT id FROM property WHERE type = '%1$sIdRef') THEN\n"
+				+ "      (SELECT name FROM %1$s WHERE id = %2$s.value)\n";
+
+		// human readable entity property values
+		this.statement.executeUpdate("CREATE VIEW vPropertyValue AS SELECT\n"
+				+ "  (SELECT name FROM entity WHERE id = propertyValue.entityId) AS entityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id = "
+				+ "(SELECT entityTypeId FROM entity WHERE id = propertyValue.entityId)"
+				+ ") AS entityType,\n"
+				+ "  (SELECT name FROM property WHERE id = propertyValue.propertyId) AS propertyName,\n"
+				+ "  (SELECT type FROM property WHERE id = propertyValue.propertyId) AS propertyType,\n"
+				+ "  (GROUP_CONCAT(CASE\n"
+				+ Stream.of("entity", "event").map(tableName -> String.format(idRefCase, tableName, "propertyValue"))
+						.collect(Collectors.joining())
+				+ "    ELSE\n"
+				+ "      propertyValue.value\n"
+				+ "  END, ', ')) AS value\n"
+				+ "FROM propertyValue GROUP BY entityId, propertyId ORDER BY entityId, propertyId;");
+		
+		// human readable observable events
+		this.statement.executeUpdate("CREATE VIEW vEvent AS SELECT\n"
+				+ "  name,\n"
+				+ "  (SELECT name FROM eventType WHERE id = eventTypeId) AS eventType,\n"
+				+ "  (SELECT name FROM entity WHERE id = entityId) AS entityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id =\n"
+				+ "    (SELECT entityTypeId FROM entity WHERE id = event.entityId)\n"
+				+ "  ) AS entityType,\n"
+				+ "  (SELECT name FROM entity WHERE id = sourceEntityId) AS sourceEntityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id =\n"
+				+ "    (SELECT entityTypeId FROM entity WHERE id = event.sourceEntityId)\n"
+				+ "  ) AS sourceEntityType\n"
+				+ "FROM event;");
+		
+		// human readable event chain table (extract from entity)
+		this.statement.executeUpdate("CREATE VIEW vEventChainEntity AS SELECT\n"
+				+ "  name AS eventChainName,\n"
+				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM event WHERE id IN (SELECT value FROM propertyValue WHERE"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecStimulus'))) AS stimulus,\n"
+				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM event WHERE id IN (SELECT value FROM propertyValue WHERE"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecResponse'))) AS response,\n"
+				+ "  (SELECT GROUP_CONCAT(name, ', ') FROM entity          WHERE id IN (SELECT value FROM propertyValue WHERE"
+				+ "    entityId = ecEntity.id AND propertyId = (SELECT id FROM property WHERE name = 'ecItems'   ))) AS items,\n"
+				+ "  (SELECT value FROM propertyValue WHERE entityId = ecEntity.id AND propertyId ="
+				+ "    (SELECT id FROM property WHERE name = 'ecMinItemsCompleted')) AS minItemsCompleted,\n"
+				+ "  EXISTS(SELECT value FROM propertyValue WHERE entityId = ecEntity.id AND propertyId ="
+				+ "    (SELECT id FROM property WHERE name = 'ecMinItemsCompleted')) AS isParallel\n"
+				+ "FROM entity AS ecEntity WHERE entityTypeId = (SELECT id FROM entityType WHERE entityType.name = 'EC');");
+		
+		// human readable entity specific metric instances
+		this.statement.executeUpdate("CREATE VIEW vEntityMetricInstanceValue AS SELECT\n"
+				+ "  (SELECT name FROM entity WHERE id = entityMetricInstanceValue.entityId) AS entityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id =\n"
+				+ "    (SELECT entityTypeId FROM entity WHERE id = entityMetricInstanceValue.entityId)\n"
+				+ "  ) AS entityType,\n"
+				+ "  (SELECT name FROM metric WHERE id = entityMetricInstanceValue.metricId) AS metricName,\n"
+				+ "  entityMetricInstanceValue.sqcnr,\n"
+				+ "  entityMetricInstanceValue.value\n"
+				+ "FROM entityMetricInstanceValue\n"
+				+ "ORDER BY entityId, metricId, sqcnr;");
+		
+		// human readable entity instance specific metrics
+		this.statement.executeUpdate("CREATE VIEW vEntityInstanceMetricValue AS SELECT\n"
+				+ "  (SELECT name FROM entity WHERE id = entityInstanceMetricValue.entityId) AS entityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id =\n"
+				+ "    (SELECT entityTypeId FROM entity WHERE id = entityInstanceMetricValue.entityId)\n"
+				+ "  ) AS entityType,\n"
+				+ "  entityInstanceMetricValue.entityInstance,\n"
+				+ "  (SELECT name FROM metric WHERE id = entityInstanceMetricValue.metricId) AS metricName,\n"
+				+ "  entityInstanceMetricValue.value\n"
+				+ "FROM entityInstanceMetricValue\n"
+				+ "ORDER BY entityId, entityInstance, metricId;");
+		
+		// human readable entity specific metrics
+		this.statement.executeUpdate("CREATE VIEW vEntityMetricValue AS SELECT\n"
+				+ "  (SELECT name FROM entity WHERE id = entityMetricValue.entityId) AS entityName,\n"
+				+ "  (SELECT name FROM entityType WHERE id =\n"
+				+ "    (SELECT entityTypeId FROM entity WHERE id = entityMetricValue.entityId)\n"
+				+ "  ) AS entityType,\n"
+				+ "  (SELECT name FROM metric WHERE id = entityMetricValue.metricId) AS metricName,\n"
+				+ "  entityMetricValue.value\n"
+				+ "FROM entityMetricValue\n"
+				+ "ORDER BY entityId, metricId;");
+		return this;
+	}
+	
+	private static String getPersistableTablePrefix(final boolean persistTable) {
+		return "CREATE" + (persistTable ? " " : " TEMPORARY ") + "TABLE ";
+	}
+	
+	private static String getInstRuntimeEventsQuery(final BTFEntityType entityType) {
+		final String events = BTFEntityState.getPossibleEventsFor(entityType).stream().map(e -> "'" + e.getName().toLowerCase() + "'")
+				.collect(Collectors.joining(", "));
+		return "  SELECT timestamp, sqcnr, entityId, entityInstance, sourceEntityId, sourceEntityInstance, eventTypeId\n"//
+				+ "  FROM traceEvent WHERE\n"//
+				+ "    eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + events + ")) AND\n"//
+				+ "    entityId IN (SELECT id FROM entity WHERE entityTypeId IN\n"//
+				+ "      (SELECT id FROM entityType WHERE name IN (" + entityType.getTraceAliases() + "))\n"//
+				+ "    )\n"//
+				+ "  GROUP BY entityId, entityInstance, timestamp, sqcnr";
+	}
+
+	private static String getInstEventInfosQuery(final BTFEntityType entityType) {
+		return "SELECT *, (" + String.join(" AND ", BTFEntityState.getValidityConstraints(entityType)) + ") isComplete "//
+				+ "FROM (SELECT"//
+				+ " entityId,"//
+				+ " entityInstance,"//
+				+ BTFEntityState.getPossibleEventsFor(entityType).stream().map(e -> //
+				" SUM(CASE WHEN eventTypeId = (SELECT id FROM eventType WHERE name = '" + e.getName().toLowerCase() + //
+						"') THEN 1 ELSE 0 END) " + e + "EventCount").collect(Collectors.joining(","))//
+				+ " FROM " + entityType.getName() + "InstanceRuntimeTraceEvent GROUP BY entityId, entityInstance)";
+	}
+	
+	public ATDBBuilder createOptionalAndTemporaryTables(final boolean persistOptionalTables) throws SQLException {
+		final String persistableTablePref = getPersistableTablePrefix(persistOptionalTables);
+		// create traceEvent table and indices
+		this.statement.executeUpdate(persistableTablePref + "traceEvent (\n"
+				+ "  timestamp            INTEGER,\n"
+				+ "  sqcnr                INTEGER,\n"
+				+ "  entityId             INTEGER,\n"
+				+ "  entityInstance       INTEGER,\n"
+				+ "  sourceEntityId       INTEGER,\n"
+				+ "  sourceEntityInstance INTEGER,\n"
+				+ "  eventTypeId          INTEGER,\n"
+				+ "  value                TEXT,\n"
+				+ "  PRIMARY KEY(timestamp, sqcnr)"
+				+ (persistOptionalTables ? ",\n  FOREIGN KEY(entityId, entityInstance) REFERENCES entityInstance"
+						+ ",\n  FOREIGN KEY(sourceEntityId, sourceEntityInstance) REFERENCES entityInstance"
+						+ ",\n  FOREIGN KEY(eventTypeId) REFERENCES eventType\n" : "\n")
+				+ ");");
+		this.statement.executeUpdate("CREATE INDEX traceEventIndex ON traceEvent(timestamp, sqcnr);");
+		this.statement.executeUpdate("CREATE INDEX traceEventIndexForECs ON traceEvent(entityId, eventTypeId);");
+		
+		createTemporaryEntityFilteredTraceEventTables();
+		
+		for (final BTFEntityType et : BTFEntityType.values()) {
+			// extract runtime relevant traceEvent counts per entity instance
+			this.statement.executeUpdate(persistableTablePref + et.getName() + "InstanceTraceInfo (\n"
+					+ "  entityId             INTEGER,\n"
+					+ "  entityInstance       INTEGER,\n"
+					+ BTFEntityState.getPossibleEventsFor(et).stream().map(e -> e.getName().toLowerCase() + "EventCount  INTEGER,\n").collect(Collectors.joining())
+					+ "  isComplete           BOOLEAN,\n"
+					+ "  PRIMARY KEY(entityId, entityInstance)\n"
+					+ ");");
+			// create index for better performance on trace events
+			this.statement.executeUpdate("CREATE UNIQUE INDEX " + et.getName() + "InstanceTraceInfoIndex ON " + et.getName()
+					+ "InstanceTraceInfo(entityId, entityInstance);");
+		}
+
+		// create event chain info table
+		this.statement.executeUpdate(persistableTablePref + "eventChainInstanceInfo (\n"//
+				+ "  entityId          INTEGER,\n"//
+				+ "  entityInstance    INTEGER,\n"//
+				+ "  stimulusTimestamp INTEGER,\n"//
+				+ "  stimulusSqcnr     INTEGER,\n"//
+				+ "  responseTimestamp INTEGER,\n"//
+				+ "  responseSqcnr     INTEGER,\n"//
+				+ "  isAge             BOOLEAN,\n"//
+				+ "  isReaction        BOOLEAN,\n"//
+				+ "  PRIMARY KEY(entityId, entityInstance),\n"//
+				+ "  FOREIGN KEY(stimulusTimestamp, stimulusSqcnr) REFERENCES traceEvent,\n"//
+				+ "  FOREIGN KEY(responseTimestamp, responseSqcnr) REFERENCES traceEvent"//
+				+ (persistOptionalTables ? ",\n  FOREIGN KEY(entityId, entityInstance) REFERENCES entityInstance" : "")//
+				+ "\n);");
+		
+		return this;
+	}
+	
+	public ATDBBuilder createTemporaryEntityFilteredTraceEventTables() throws SQLException {
+		for (final BTFEntityType et : BTFEntityType.values()) {
+			// collect/filter runtime relevant events per entity type
+			this.statement.executeUpdate("CREATE TEMPORARY TABLE " + et.getName() + "InstanceRuntimeTraceEvent (\n"
+					+ "  timestamp            INTEGER,\n"
+					+ "  sqcnr                INTEGER,\n"
+					+ "  entityId             INTEGER,\n"
+					+ "  entityInstance       INTEGER,\n"
+					+ "  sourceEntityId       INTEGER,\n"
+					+ "  sourceEntityInstance INTEGER,\n"
+					+ "  eventTypeId          INTEGER,\n"
+					+ "  PRIMARY KEY(timestamp, sqcnr)\n"
+					+ ");");
+			// create index for better performance on trace events
+			this.statement.executeUpdate("CREATE INDEX " + et.getName() + "InstanceRuntimeTraceEventIndex ON "
+					+ et.getName() + "InstanceRuntimeTraceEvent(entityId, entityInstance, eventTypeId);");
+		}
+		return this;
+	}
+	
+	/**
+	 * This only works if the optional tables have been persisted.
+	 * @return
+	 * @throws SQLException
+	 */
+	public ATDBBuilder createOptionalViews() throws SQLException {
+		// human readable event table
+		this.statement.executeUpdate("CREATE VIEW vTraceEvent AS SELECT\n"//
+				+ "  traceEvent.timestamp,\n"//
+				+ "  traceEvent.sqcnr,\n"//
+				+ "  (SELECT name FROM entity WHERE id = traceEvent.entityId) AS entityName,\n"//
+				+ "  (SELECT name FROM entityType WHERE id =\n"//
+				+ "    (SELECT entityTypeId FROM entity WHERE id = traceEvent.entityId)\n"//
+				+ "  ) AS entityType,\n"//
+				+ "  traceEvent.entityInstance,\n"//
+				+ "  (SELECT name FROM entity WHERE id = traceEvent.sourceEntityId) AS sourceEntityName,\n"//
+				+ "  (SELECT name FROM entityType WHERE id =\n"//
+				+ "    (SELECT entityTypeId FROM entity WHERE id = traceEvent.sourceEntityId)\n"//
+				+ "  ) AS sourceEntityType,\n"//
+				+ "  traceEvent.sourceEntityInstance,\n"//
+				+ "  (SELECT name FROM eventType WHERE id = traceEvent.eventTypeId) AS eventType,\n"//
+				+ "  traceEvent.value\n"//
+				+ "FROM traceEvent;");
+
+		for (final BTFEntityType et : BTFEntityType.values()) {
+			final String reDBName = et.getName() + "InstanceRuntimeTraceEvent";
+			// human readable intermediate view for all runtime relevant events per entity instance
+			this.statement.executeUpdate("CREATE VIEW v" + reDBName + " AS SELECT\n"//
+					+ "  timestamp,\n"//
+					+ "  sqcnr,\n"//
+					+ "  (SELECT name FROM entity WHERE id = entityId) AS " + et.getUCName() + "Name,\n"//
+					+ "  entityInstance,\n"//
+					+ "  (SELECT name FROM entity WHERE id = sourceEntityId) AS sourceEntityName,\n"//
+					+ "  sourceEntityInstance,\n"//
+					+ "  (SELECT name FROM eventType WHERE id = " + "eventTypeId) AS eventType\n"//
+					+ "FROM (\n" + getInstRuntimeEventsQuery(et) + "\n);");
+			// human readable intermediate view for all runtime relevant traceEvent counts per entity instance
+			final String eiDBName = et.getName() + "InstanceTraceInfo";
+			final String eventCountColumns = BTFEntityState.getPossibleEventsFor(et).stream()
+					.map(ev -> eiDBName + "." + ev.getName().toLowerCase() + "EventCount").collect(Collectors.joining(",\n  "));
+			this.statement.executeUpdate("CREATE VIEW v" + eiDBName + " AS SELECT\n"//
+					+ "  (SELECT name FROM entity WHERE id = " + eiDBName + ".entityId) AS " + et.getUCName() + "Name,\n"//
+					+ "  " + eiDBName + ".entityInstance,\n"//
+					+ "  " + eventCountColumns + ",\n"//
+					+ "  " + eiDBName + ".isComplete\n"//
+					+ "FROM " + eiDBName + ";");
+		}
+
+		// human readable event chain instance info table
+		this.statement.executeUpdate("CREATE VIEW vEventChainInstanceInfo AS SELECT\n"//
+				+ "  (SELECT name FROM entity WHERE id = entityId) AS eventChainName,\n"//
+				+ "  entityInstance AS ecInstance,\n"//
+				+ "  stimulusTimestamp,\n"//
+				+ "  (SELECT name FROM entity WHERE id = (SELECT entityId FROM traceEvent WHERE timestamp = stimulusTimestamp "//
+				+ "AND sqcnr = stimulusSqcnr)) AS stimulusEntityName,\n"//
+				+ "  (SELECT entityInstance FROM traceEvent WHERE timestamp = stimulusTimestamp "//
+				+ "AND sqcnr = stimulusSqcnr) AS stimulusEntityInstance,\n"//
+				+ "  (SELECT name FROM eventType WHERE id = (SELECT eventTypeId FROM traceEvent WHERE timestamp = stimulusTimestamp "//
+				+ "AND sqcnr = stimulusSqcnr)) AS stimulusEvent,\n"//
+				+ "  responseTimestamp,\n"//
+				+ "  (SELECT name FROM entity WHERE id = (SELECT entityId FROM traceEvent WHERE timestamp = responseTimestamp "//
+				+ "AND sqcnr = responseSqcnr)) AS responseEntityName,\n"//
+				+ "  (SELECT entityInstance FROM traceEvent WHERE timestamp = responseTimestamp "//
+				+ "AND sqcnr = responseSqcnr) AS responseEntityInstance,\n"//
+				+ "  (SELECT name FROM eventType WHERE id = (SELECT eventTypeId FROM traceEvent WHERE timestamp = responseTimestamp "//
+				+ "AND sqcnr = responseSqcnr)) AS responseEvent,\n"//
+				+ "  (CASE WHEN isAge AND isReaction THEN 'age/reaction' WHEN isAge THEN 'age' "//
+				+ "WHEN isReaction THEN 'reaction' END) AS latencyType\n"//
+				+ "FROM eventChainInstanceInfo;");
+		return this;
+	}
+	
+	public void autoPopulateEntityFilteredTraceEventTables() throws SQLException {
+		for (final BTFEntityType et : BTFEntityType.values()) {
+			// collect/filter runtime relevant events per entity instance
+			this.statement.executeUpdate("INSERT INTO " + et.getName() + "InstanceRuntimeTraceEvent\n" + getInstRuntimeEventsQuery(et) + ";");
+			// extract runtime relevant traceEvent counts per entity instance
+			this.statement.executeUpdate("INSERT INTO " + et.getName() + "InstanceTraceInfo\n" + getInstEventInfosQuery(et) + ";");
+		}
+	}
+	
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBMetricCalculator.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBMetricCalculator.java
new file mode 100644
index 0000000..582b5c9
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ATDBMetricCalculator.java
@@ -0,0 +1,168 @@
+package org.eclipse.app4mc.amalthea._import.btf;
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFCombiState;
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFCountMetric;
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFEntityState;
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFEntityType;
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFInterInstanceMetric;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+public class ATDBMetricCalculator implements IRunnableWithProgress {
+	
+	private final Connection con;
+	
+	public ATDBMetricCalculator(final Connection con) {
+		this.con = con;
+	}
+
+	@Override
+	public void run(IProgressMonitor monitor) throws InvocationTargetException {
+		monitor.beginTask("Calculating metrics...", 100);
+		try {
+			final PreparedStatement metricStmt = this.con.prepareStatement("INSERT INTO metric(name, dimension) VALUES(?, ?);");
+			final Statement statement = this.con.createStatement();
+			final Set<String> entityInstanceTimeMetrics = new LinkedHashSet<>();
+	
+			// for each state: add a '[state]Time' metric signifying how long the entity instance was in that state
+			for (final BTFEntityState state : BTFEntityState.actStates) {
+				entityInstanceTimeMetrics.add(state + "Time");
+				metricStmt.setString(1, state + "Time");
+				metricStmt.setString(2, "time");
+				metricStmt.addBatch();
+				final List<String> entityInstanceStateTimesQuerys = new ArrayList<>();
+				state.entityType2InOutEvents.forEach((entityType, inOut) -> {
+					// map and collect events as SQL list
+					final String incomingEvents = inOut.getKey().stream().map(e -> "'" + e.getName().toLowerCase() + "'").collect(Collectors.joining(", "));
+					// map and collect events as SQL list
+					final String outgoingEvents = inOut.getValue().stream().map(e -> "'" + e.getName().toLowerCase() + "'").collect(Collectors.joining(", "));
+					final String query = "SELECT"//
+							+ "  entityId,"//
+							+ "  entityInstance,"//
+							+ "  IFNULL(SUM(CASE"//
+							+ "    WHEN eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + incomingEvents + ")) THEN -timestamp"//
+							+ "    WHEN eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + outgoingEvents + ")) THEN timestamp"//
+							+ "  END), 0) " + state + "Time "//
+							+ "FROM " + entityType.getName() + "InstanceRuntimeTraceEvent GROUP BY entityId, entityInstance "//
+							+ "HAVING (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+							+ "  entityId       = " + entityType.getName() + "InstanceRuntimeTraceEvent.entityId AND "//
+							+ "  entityInstance = " + entityType.getName() + "InstanceRuntimeTraceEvent.entityInstance)";
+					entityInstanceStateTimesQuerys.add(query);
+				});
+				final String entityInstanceMetricQuery = "INSERT INTO entityInstanceMetricValue SELECT "//
+						+ "  entityId,"//
+						+ "  entityInstance,"//
+						+ "  (SELECT id FROM metric WHERE name = '" + state + "Time'),"//
+						+ "  " + state + "Time FROM (" + String.join(" UNION ", entityInstanceStateTimesQuerys)//
+						+ ");";
+				statement.addBatch(entityInstanceMetricQuery);
+			}
+	
+			// consider combi states for processes
+			for (final BTFCombiState cState : BTFCombiState.values()) {
+				entityInstanceTimeMetrics.add(cState + "Time");
+				metricStmt.setString(1, cState + "Time");
+				metricStmt.setString(2, "time");
+				metricStmt.addBatch();
+				final String stateTimes = cState.states.stream().map(s -> "'" + s + "Time'").collect(Collectors.joining(", "));
+				statement.addBatch("INSERT INTO entityInstanceMetricValue SELECT "//
+						+ "  entityId,"//
+						+ "  entityInstance,"//
+						+ "  (SELECT id FROM metric WHERE name = '" + cState + "Time'),"//
+						+ "  (SELECT SUM(CAST (value AS INTEGER)) FROM entityInstanceMetricValue WHERE "//
+						+ "    entityId = " + BTFEntityType.processsss.getName() + "InstanceTraceInfo.entityId AND "//
+						+ "    entityInstance = " + BTFEntityType.processsss.getName() + "InstanceTraceInfo.entityInstance AND "//
+						+ "    metricId IN (SELECT id FROM metric WHERE name IN (" + stateTimes + "))"//
+						+ "  )"//
+						+ "FROM " + BTFEntityType.processsss.getName() + "InstanceTraceInfo WHERE isComplete;");
+			}
+	
+			// calculate inter-instance metrics
+			for (final BTFInterInstanceMetric metric : BTFInterInstanceMetric.values()) {
+				entityInstanceTimeMetrics.add(metric.toString());
+				metricStmt.setString(1, metric.toString());
+				metricStmt.setString(2, "time");
+				metricStmt.addBatch();
+				final List<String> iiMetricQueries = new ArrayList<>();
+				metric.entityType2FirstAndSecond.forEach((entityType, firstAndSecondInstEvent) -> {
+					final String query = "SELECT A.entityId, A.entityInstance, SUM(B.timestamp - A.timestamp) AS " + metric + " "//
+							+ "FROM (SELECT * FROM " + entityType.getName() + "InstanceRuntimeTraceEvent) AS A "//
+							+ "INNER JOIN " + entityType.getName() + "InstanceRuntimeTraceEvent AS B ON "//
+							+ "  B.entityId = A.entityId AND B.entityInstance = A.entityInstance + 1 "//
+							+ "  WHERE A.eventTypeId = (SELECT id FROM eventType WHERE name = '" + firstAndSecondInstEvent.getKey() + "') AND "//
+							+ "        B.eventTypeId = (SELECT id FROM eventType WHERE name = '" + firstAndSecondInstEvent.getValue() + "') "//
+							+ "  GROUP BY A.entityId, A.entityInstance "//
+							+ "  HAVING (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+							+ "      entityId       = A.entityId AND "//
+							+ "      entityInstance = A.entityInstance) AND "//
+							+ "    (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+							+ "      entityId       = B.entityId AND "//
+							+ "      entityInstance = B.entityInstance)";
+					iiMetricQueries.add(query);
+				});
+				statement.addBatch("INSERT INTO entityInstanceMetricValue SELECT "//
+						+ "  entityId,"//
+						+ "  entityInstance,"//
+						+ "  (SELECT id FROM metric WHERE name = '" + metric + "'),"//
+						+ "  " + metric + " FROM (" + String.join(" UNION ", iiMetricQueries)//
+						+ ");");
+			}
+	
+			// calculate entity metrics min max avg for all time metric values
+			final List<String> mma = Arrays.asList("Min", "Max", "Avg");
+			for (final String entityInstanceTimeMetric : entityInstanceTimeMetrics) {
+				for (final String kind : mma) {
+					metricStmt.setString(1, entityInstanceTimeMetric + "_" + kind);
+					metricStmt.setString(2, "time");
+					metricStmt.addBatch();
+				}
+			}
+			for (final String kind : mma) {
+				String aggregateFunction = kind.toUpperCase() + "(CAST(value AS INTEGER))";
+				if (kind.equalsIgnoreCase("AVG")) {
+					aggregateFunction = "printf('%.2f'," + aggregateFunction + ")";
+				}
+				statement.addBatch("INSERT INTO entityMetricValue SELECT "//
+						+ "  entityId,"//
+						+ "  (SELECT id FROM metric WHERE name = (SELECT name FROM metric WHERE id = metricId) || '_" + kind + "'),"//
+						+ "  " + aggregateFunction + " FROM entityInstanceMetricValue WHERE "//
+						+ "metricId IN (SELECT id FROM metric WHERE dimension = 'time') GROUP BY entityId, metricId;");
+			}
+	
+			// insert entity specific count metrics
+			for (final BTFCountMetric cm : BTFCountMetric.values()) {
+				metricStmt.setString(1, cm.toString());
+				metricStmt.setString(2, "count");
+				metricStmt.addBatch();
+				statement.addBatch("INSERT INTO entityMetricValue SELECT "//
+						+ "  entityId,"//
+						+ "  (SELECT id FROM metric WHERE name = '" + cm + "') AS metricId,"//
+						+ "  SUM(" + cm.eventToCount.toString().toLowerCase() + "EventCount) AS value "//
+						+ "FROM " + cm.entityType.getName() + "InstanceTraceInfo GROUP BY entityId;");
+			}
+	
+			// execute all statements
+			this.con.setAutoCommit(false);
+			metricStmt.executeBatch();
+			monitor.worked(70);
+			statement.executeBatch();
+			monitor.worked(30);
+			this.con.setAutoCommit(true);
+		} catch (SQLException e) {
+			throw new InvocationTargetException(e);
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/BTFImporter.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/BTFImporter.java
new file mode 100644
index 0000000..c2fea07
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/BTFImporter.java
@@ -0,0 +1,289 @@
+package org.eclipse.app4mc.amalthea._import.btf;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Scanner;
+import java.util.Set;
+
+import org.eclipse.app4mc.amalthea._import.btf.model.BTFEntityType;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+public class BTFImporter implements IRunnableWithProgress {
+	
+	private final String btfFile;
+	private final Connection con;
+	
+	public BTFImporter(final Connection con, final String btfFile) {
+		this.con = con;
+		this.btfFile = btfFile;
+	}
+	
+	@Override
+	public void run(final IProgressMonitor progressMonitor) throws InvocationTargetException {
+		SubMonitor subMon = SubMonitor.convert(progressMonitor, "Importing BTF file...", 6);
+		final SubMonitor readingBTFMonitor = subMon.split(5);
+		readingBTFMonitor.beginTask("Reading BTF file...", 10_000);
+		try (final FileInputStream fis = new FileInputStream(btfFile); final Scanner sc = new Scanner(fis, "UTF-8")) {
+			final long fileSize = new File(btfFile).length();
+			final PreparedStatement metaStmt = con.prepareStatement("INSERT INTO metaInformation VALUES(?, ?);");
+			final PreparedStatement entTStmt = con.prepareStatement("INSERT INTO entityType(name) VALUES(?);");
+			final PreparedStatement entStmt = con.prepareStatement("INSERT INTO entity(name, entityTypeId) VALUES(?,"//
+					+ "(SELECT id FROM entityType WHERE name = ?));");
+			final PreparedStatement instStmt = con.prepareStatement("INSERT INTO entityInstance VALUES("//
+					+ "(SELECT id FROM entity WHERE name = ?), ?);");
+			final PreparedStatement evTStmt = con.prepareStatement("INSERT INTO eventType(name) VALUES(?);");
+			final PreparedStatement evStmt = con.prepareStatement("INSERT INTO traceEvent VALUES(?, ?,"//
+					+ "(SELECT id FROM entity WHERE name = ?), ?,"//
+					+ "(SELECT id FROM entity WHERE name = ?), ?,"//
+					+ "(SELECT id FROM eventType WHERE name = ?), ?)");
+			long currentTimestamp = Long.MIN_VALUE;
+			int currentSQCNR = 0;
+			String currentECU = "";
+			String currentProcessor = "";
+			long currentLineNumber = 0;
+			long lineLengthSum = 0;
+			long avgLineLength = 64;
+			while (sc.hasNextLine()) {
+				currentLineNumber++;
+				final String line = sc.nextLine();
+				if (!line.startsWith("#")) {
+					final String[] fields = line.split(",");
+					if (fields.length > 6) {
+						final long newTimestamp = Long.parseLong(fields[0]);
+						final String entityType = fields[3];
+						final String entityName = fields[4];
+						final int entityInstance = Integer.parseInt(fields[5]);
+						final String sourceName = fields[1];
+						final int sourceInstance = Integer.parseInt(fields[2]);
+						final String eventType = fields[6];
+						final Optional<String> value = fields.length > 7 ? Optional.of(fields[7]) : Optional.empty();
+						insertEntity(entTStmt, entityName, entityType);
+						if (eventType.equalsIgnoreCase("tag") && value.isPresent()) {
+							String sourceType = "";
+							switch (value.get()) {
+							case "ECU_INIT":
+								sourceType = "ECU";
+								currentECU = sourceName;
+								break;
+							case "PROCESSOR_INIT":
+								sourceType = "Processor";
+								currentProcessor = sourceName;
+								appendToProperty(currentECU, "processors", "entityIdRef", sourceName);
+								break;
+							case "CORE_INIT":
+								sourceType = "C";
+								appendToProperty(currentProcessor, "cores", "entityIdRef", sourceName);
+								break;
+							case "SIG_INIT_VALUE":
+								sourceType = "SIG";
+								if (fields.length > 8) {
+									setProperty(sourceName, "initialValue", "object", fields[8]);
+								}
+								break;
+							default:
+								setProperty(sourceName, "tag", "object", value.get());
+							}
+							if (!sourceType.isEmpty()) {
+								insertEntity(entTStmt, sourceName, sourceType);
+							}
+						} else if (eventType.equalsIgnoreCase("set_frequence") && value.isPresent()) {
+							setProperty(entityName, "frequencyInHz", "long", value.get());
+							continue;
+						} else if ((eventType.equalsIgnoreCase("start") || eventType.equalsIgnoreCase("stop"))
+								&& entityType.equals("SYS")) {
+							setProperty(entityName, "system" + eventType.substring(0, 1).toUpperCase() + eventType.substring(1) + "Time",
+									"time", "" + newTimestamp);
+							continue;
+						}
+						if (BTFEntityType.processsss.isTraceAlias(entityType)//
+								&& "C".equals(entity2Type.getOrDefault(sourceName, ""))//
+								&& (!entity2property2Value.containsKey(entityName)//
+										|| !entity2property2Value.get(entityName).containsKey("executingCore"))) {
+							setProperty(entityName, "executingCore", "entityIdRef", sourceName);
+						}
+						if (BTFEntityType.runnabless.isTraceAlias(entityType)//
+								&& BTFEntityType.processsss.isTraceAlias(entity2Type.getOrDefault(sourceName, ""))//
+								&& (!entity2property2Value.containsKey(sourceName) //
+										|| !entity2property2Value.get(sourceName).containsKey("runnables") //
+										|| !entity2property2Value.get(sourceName).get("runnables").contains(entityName))) {
+							appendToProperty(sourceName, "runnables", "entityIdRef", entityName);
+						}
+						if (eventType.equalsIgnoreCase("activate") && BTFEntityType.processsss.isTraceAlias(entityType)) {
+							insertEntity(entTStmt, sourceName, "STI");
+						} else {
+							insertEntity(entTStmt, sourceName, "");
+						}
+						insertEntityInstance(instStmt, sourceName, sourceInstance);
+						insertEntityInstance(instStmt, entityName, entityInstance);
+						if (eventType.equalsIgnoreCase("tag")) {
+							continue;
+						}
+						if (newTimestamp > currentTimestamp) {
+							currentSQCNR = 0;
+							currentTimestamp = newTimestamp;
+						} else {
+							currentSQCNR++;
+						}
+						insertEventType(evTStmt, eventType);
+						evStmt.setLong(1, currentTimestamp);
+						evStmt.setInt(2, currentSQCNR);
+						evStmt.setString(3, entityName);
+						evStmt.setInt(4, entityInstance);
+						evStmt.setString(5, sourceName);
+						evStmt.setInt(6, sourceInstance);
+						evStmt.setString(7, eventType);
+						if (value.isPresent()) {
+							evStmt.setString(8, value.get());
+						} else {
+							evStmt.setNull(8, Types.VARCHAR);
+						}
+						evStmt.addBatch();
+					}
+				} else {
+					if (line.startsWith("#timeScale")) {
+						metaStmt.setString(1, "timeBase");
+						metaStmt.setString(2, line.substring(11));
+						metaStmt.addBatch();
+					} else if (line.startsWith("#simulation_duration")) {
+						setProperty("SIM", "simulationDuration", "time", line.substring(21, line.lastIndexOf(' ')));
+					}
+				}
+				if ((currentLineNumber % (1 << 8)) == 0) {
+					lineLengthSum += line.length();
+					if ((currentLineNumber % (1 << 16)) == 0) {
+						avgLineLength = ((avgLineLength + (lineLengthSum >> 8)) >> 1);
+						lineLengthSum = 0;
+						final long numberOfLines = fileSize / avgLineLength;
+						readingBTFMonitor.setWorkRemaining(10_000 - (int)Math.min(10_000, ((currentLineNumber * 10_000) / numberOfLines)));
+					}
+				}
+			}
+			readingBTFMonitor.done();
+			final SubMonitor writeEventsMonitor = subMon.split(1);
+			writeEventsMonitor.beginTask("Writing events to data base...", 1);
+			con.setAutoCommit(false);
+			metaStmt.executeBatch();
+			entTStmt.executeBatch();
+			executeEntityInsertStatements(entStmt);
+			instStmt.executeBatch();
+			evTStmt.executeBatch();
+			evStmt.executeBatch();
+			executePropertyInsertStatements(con.createStatement());
+			con.setAutoCommit(true);
+			writeEventsMonitor.done();
+		} catch (final IOException | SQLException e) {
+			throw new InvocationTargetException(e);
+		}
+	}
+
+	private final Map<String, String> entity2Type = new LinkedHashMap<>();
+	private final Set<String> entityTypes = new HashSet<>();
+
+	private void insertEntity(final PreparedStatement tStmt, final String name, final String entityType) throws SQLException {
+		if ((!entityType.isEmpty()) && entityTypes.add(entityType)) {
+			tStmt.setString(1, entityType);
+			tStmt.addBatch();
+		}
+		entity2Type.compute(name, (k, v) -> ((v == null) || v.isEmpty()) ? entityType : v);
+	}
+
+	private void executeEntityInsertStatements(final PreparedStatement eStmt) throws SQLException {
+		for (final Entry<String, String> entry : entity2Type.entrySet()) {
+			final String entityName = entry.getKey();
+			final String entityType = entry.getValue();
+			eStmt.setString(1, entityName);
+			eStmt.setString(2, entityType);
+			eStmt.addBatch();
+		}
+		eStmt.executeBatch();
+	}
+
+	private final Set<String> instNames = new HashSet<>();
+
+	private void insertEntityInstance(final PreparedStatement stmt, final String name, final int inst) throws SQLException {
+		final String srcInstName = name + inst;
+		if (instNames.add(srcInstName)) {
+			stmt.setString(1, name);
+			stmt.setInt(2, inst);
+			stmt.addBatch();
+		}
+	}
+
+	private final Set<String> eventTypes = new HashSet<>();
+
+	private void insertEventType(final PreparedStatement stmt, final String name) throws SQLException {
+		if (eventTypes.add(name)) {
+			stmt.setString(1, name);
+			stmt.addBatch();
+		}
+	}
+
+	private void appendToProperty(final String entityName, final String propertyName, final String propertyType,
+			final String propertyValue) {
+		setProperty(entityName, propertyName, propertyType, propertyValue, true);
+	}
+
+	private void setProperty(final String entityName, final String propertyName, final String propertyType,
+			final String propertyValue) {
+		setProperty(entityName, propertyName, propertyType, propertyValue, false);
+	}
+
+	private final Map<String, Map<String, List<String>>> entity2property2Value = new LinkedHashMap<>();
+
+	private final Map<String, String> properties = new LinkedHashMap<>();
+
+	private void setProperty(final String entityName, final String propertyName, final String propertyType,
+			final String propertyValue, final boolean append) {
+		properties.putIfAbsent(propertyName, propertyType);
+		final Map<String, List<String>> property2Value = entity2property2Value.computeIfAbsent(entityName, k -> new LinkedHashMap<>());
+		final List<String> values = property2Value.computeIfAbsent(propertyName, k -> new ArrayList<>());
+		if (!append) {
+			values.clear();
+		}
+		values.add(propertyValue);
+	}
+
+	private void executePropertyInsertStatements(final Statement stmt) throws SQLException {
+		final List<String> statements = new ArrayList<>();
+		properties.forEach((propertyName, propertyType) -> statements.add("INSERT INTO property(name, type) VALUES('"//
+				+ propertyName + "', '" + propertyType + "');"));
+		entity2property2Value.forEach((entityName, property2Value) -> property2Value.forEach((propertyName, propertyValue) -> {
+			final List<String> propertyValueStrings = new ArrayList<>();
+			final String propertyType = properties.get(propertyName);
+			if (propertyType.endsWith("IdRef")) {
+				final String tableName = propertyType.substring(0, propertyType.lastIndexOf("IdRef"));
+				propertyValue.forEach(pv -> propertyValueStrings.add("(SELECT id FROM " + tableName + " WHERE name = '" + pv + "')"));
+			} else {
+				propertyValueStrings.add("'" + String.join(", ", propertyValue) + "'");
+			}
+			for (int i = 0; i < propertyValueStrings.size(); i++) {
+				statements.add("INSERT INTO propertyValue(entityId, propertyId, sqcnr, value) VALUES("//
+						+ "(SELECT id FROM entity   WHERE name = '" + entityName + "'), "//
+						+ "(SELECT id FROM property WHERE name = '" + propertyName + "'), "//
+						+ i + ","//
+						+ propertyValueStrings.get(i) + ");");
+			}
+		}));
+		for (final String st : statements) {
+			stmt.addBatch(st);
+		}
+		stmt.executeBatch();
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ImportTransformation.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ImportTransformation.java
new file mode 100644
index 0000000..e7b3217
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/ImportTransformation.java
@@ -0,0 +1,73 @@
+/**
+ ********************************************************************************
+ * Copyright (c) 2015 Timing-Architects Embedded Systems GmbH and others.
+ * 
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *     Timing-Architects Embedded Systems GmbH - initial API and implementation
+ ********************************************************************************
+ */
+
+package org.eclipse.app4mc.amalthea._import.btf;
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+
+public class ImportTransformation implements IRunnableWithProgress {
+	
+	private final String btfFile;
+	private final String atdbFile;
+	
+	public ImportTransformation(final String source, final String target) {
+		if (source.endsWith(".btf") && target.endsWith(".atdb")) {
+			this.btfFile = source;
+			this.atdbFile = target;
+		} else {
+			this.btfFile = "";
+			this.atdbFile = "";
+		}
+	}
+
+	@Override
+	public void run(final IProgressMonitor progressMonitor) throws InvocationTargetException {
+		try {
+			if (!this.btfFile.isEmpty() && !this.atdbFile.isEmpty()) {
+				final SubMonitor subMon = SubMonitor.convert(progressMonitor, "Converting BTF trace to ATDB...", 100);
+				final SubMonitor createATDBMonitor = subMon.split(1);
+				createATDBMonitor.beginTask("Creating empty ATDB...", 1);
+				final ATDBBuilder atdbBuilder = new ATDBBuilder(this.atdbFile)
+						.createBasicDBStructure().createBasicViews()
+						.createOptionalAndTemporaryTables(true).createOptionalViews();
+				createATDBMonitor.done();
+				
+				final SubMonitor btfImportMonitor = subMon.split(69);
+				final Connection con = atdbBuilder.getCurrentConnection();
+				final BTFImporter btfImporter = new BTFImporter(con, this.btfFile);
+				btfImporter.run(btfImportMonitor);
+				btfImportMonitor.done();
+				
+				final SubMonitor metricCalcMonitor = subMon.split(30);
+				atdbBuilder.autoPopulateEntityFilteredTraceEventTables();
+				final ATDBMetricCalculator metricCalc = new ATDBMetricCalculator(con);
+				metricCalc.run(metricCalcMonitor);
+				atdbBuilder.closeATDB();
+				metricCalcMonitor.done();
+			}
+		} catch (SQLException e) {
+			throw new InvocationTargetException(e);
+		} finally {
+			progressMonitor.done();
+		}
+	}
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCombiState.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCombiState.java
new file mode 100644
index 0000000..c72a47f
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCombiState.java
@@ -0,0 +1,17 @@
+package org.eclipse.app4mc.amalthea._import.btf.model;
+
+import java.util.EnumSet;
+
+public enum BTFCombiState {
+
+	coreExecution(BTFEntityState.running, BTFEntityState.polling),
+	netExecution(BTFEntityState.running, BTFEntityState.polling, BTFEntityState.waiting),
+	grossExecution(BTFEntityState.running, BTFEntityState.polling, BTFEntityState.parking, BTFEntityState.waiting, BTFEntityState.ready);
+
+	public final EnumSet<BTFEntityState> states;
+
+	private BTFCombiState(final BTFEntityState firstState, final BTFEntityState... otherStates) {
+		this.states = EnumSet.of(firstState, otherStates);
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCountMetric.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCountMetric.java
new file mode 100644
index 0000000..3a50866
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFCountMetric.java
@@ -0,0 +1,32 @@
+package org.eclipse.app4mc.amalthea._import.btf.model;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.app4mc.amalthea.model.ProcessEventType;
+import org.eclipse.app4mc.amalthea.model.RunnableEventType;
+import org.eclipse.emf.common.util.Enumerator;
+
+public enum BTFCountMetric {
+
+	activations(ProcessEventType.ACTIVATE),
+	preemptions(ProcessEventType.PREEMPT),
+	suspensions(RunnableEventType.SUSPEND);
+
+	public final Enumerator eventToCount;
+	public final BTFEntityType entityType;
+
+	private BTFCountMetric(final Enumerator eventToCount) {
+		this.eventToCount = eventToCount;
+		String entityTypeName = eventToCount.getClass().getSimpleName();
+		entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase();
+		this.entityType = BTFEntityType.getForName(entityTypeName);
+	}
+	
+	public static List<Enumerator> getInvolvedBTFEventsForEntityType(final BTFEntityType entityType) {
+		return Stream.of(BTFCountMetric.values()).filter(cm -> cm.entityType == entityType)
+				.map(cm -> cm.eventToCount).collect(Collectors.toList());
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityState.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityState.java
new file mode 100644
index 0000000..7cd950e
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityState.java
@@ -0,0 +1,92 @@
+package org.eclipse.app4mc.amalthea._import.btf.model;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.app4mc.amalthea.model.ProcessEventType;
+import org.eclipse.app4mc.amalthea.model.RunnableEventType;
+import org.eclipse.emf.common.util.Enumerator;
+
+public enum BTFEntityState {
+
+	// initial state
+	notInitialized(new SimpleEntry<>(Collections.emptyList(), Arrays.asList(RunnableEventType.START)), //
+			new SimpleEntry<>(Collections.emptyList(), Arrays.asList(ProcessEventType.ACTIVATE))),
+	// in BTF this is actually the "active" state
+	startDelay(new SimpleEntry<>(Arrays.asList(ProcessEventType.ACTIVATE), Arrays.asList(ProcessEventType.START))),
+	running(new SimpleEntry<>(
+					Arrays.asList(RunnableEventType.START, RunnableEventType.RESUME),
+					Arrays.asList(RunnableEventType.TERMINATE, RunnableEventType.SUSPEND)), //
+			new SimpleEntry<>(
+					Arrays.asList(ProcessEventType.START, ProcessEventType.RESUME, ProcessEventType.RUN),
+					Arrays.asList(ProcessEventType.TERMINATE, ProcessEventType.PREEMPT, ProcessEventType.POLL, ProcessEventType.WAIT))),
+	polling(new SimpleEntry<>(Arrays.asList(ProcessEventType.POLL, ProcessEventType.POLL_PARKING), Arrays.asList(ProcessEventType.RUN, ProcessEventType.PARK))),
+	parking(new SimpleEntry<>(Arrays.asList(ProcessEventType.PARK), Arrays.asList(ProcessEventType.POLL_PARKING, ProcessEventType.RELEASE_PARKING))),
+	waiting(new SimpleEntry<>(Arrays.asList(ProcessEventType.WAIT), Arrays.asList(ProcessEventType.RELEASE))),
+	ready(new SimpleEntry<>(Arrays.asList(RunnableEventType.SUSPEND), Arrays.asList(RunnableEventType.RESUME)), //
+			new SimpleEntry<>(Arrays.asList(ProcessEventType.PREEMPT, ProcessEventType.RELEASE, ProcessEventType.RELEASE_PARKING),
+					Arrays.asList(ProcessEventType.RESUME))),
+	// meta state (not represented as combi state for simplicity)
+	response(new SimpleEntry<>(Arrays.asList(ProcessEventType.ACTIVATE), Arrays.asList(ProcessEventType.TERMINATE))),
+	// final state
+	terminated(new SimpleEntry<>(Arrays.asList(RunnableEventType.TERMINATE), Collections.emptyList()), //
+			new SimpleEntry<>(Arrays.asList(ProcessEventType.TERMINATE), Collections.emptyList()));
+	
+	public final Map<BTFEntityType, Entry<List<Enumerator>, List<Enumerator>>> entityType2InOutEvents;
+	// list of all states excluding initial and final states
+	public static final List<BTFEntityState> actStates = Stream.of(values())
+			.filter(p -> p.entityType2InOutEvents.values().stream().noneMatch(e -> e.getKey().isEmpty()))
+			.filter(p -> p.entityType2InOutEvents.values().stream().noneMatch(e -> e.getValue().isEmpty()))
+			.collect(Collectors.toList());
+	
+	@SafeVarargs
+	private BTFEntityState(final Entry<List<Enumerator>, List<Enumerator>>... inOutEvents) {
+		this.entityType2InOutEvents = new LinkedHashMap<>();
+		Stream.of(inOutEvents).forEach(e -> {
+			String entityTypeName = e.getKey().stream().findFirst().orElseGet(e.getValue().stream().findFirst()::get).getClass().getSimpleName();
+			entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase();
+			this.entityType2InOutEvents.put(BTFEntityType.getForName(entityTypeName), e);
+		});
+	}
+	
+	public static List<String> getValidityConstraints(final BTFEntityType entityType) {
+		final List<String> validityConstraints = new ArrayList<>();
+		// events for initial and final states must occur exactly once
+		Stream.of(values()).filter(s -> !actStates.contains(s)).map(s -> s.entityType2InOutEvents.get(entityType))
+				.filter(Objects::nonNull).forEach(entry -> {
+					entry.getKey().forEach(e -> validityConstraints.add(e.getName().toLowerCase() + "EventCount = 1"));
+					entry.getValue().forEach(e -> validityConstraints.add(e.getName().toLowerCase() + "EventCount = 1"));
+				});
+		// sum of incoming events must equal sum of outgoing events (excluding loop events)
+		actStates.stream().map(s -> s.entityType2InOutEvents.get(entityType)).filter(Objects::nonNull).forEach(entry -> {
+			final Set<Enumerator> loopEvents = new LinkedHashSet<>(entry.getKey());
+			loopEvents.retainAll(entry.getValue());
+			final String left = entry.getKey().stream().filter(e -> !loopEvents.contains(e)).map(e -> e.getName().toLowerCase() + "EventCount")
+					.collect(Collectors.joining(" + "));
+			final String right = entry.getValue().stream().filter(e -> !loopEvents.contains(e)).map(e -> e.getName().toLowerCase() + "EventCount")
+					.collect(Collectors.joining(" + "));
+			validityConstraints.add(left + " = " + right);
+		});
+		return validityConstraints;
+	}
+
+	public static Set<Enumerator> getPossibleEventsFor(final BTFEntityType entityType) {
+		final Set<Enumerator> result = new LinkedHashSet<>(BTFCountMetric.getInvolvedBTFEventsForEntityType(entityType));
+		Stream.of(values()).map(s -> s.entityType2InOutEvents.get(entityType))
+				.filter(Objects::nonNull).flatMap(e -> Stream.concat(e.getKey().stream(), e.getValue().stream())).distinct()
+				.forEach(result::add);
+		return result;
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityType.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityType.java
new file mode 100644
index 0000000..68da91f
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFEntityType.java
@@ -0,0 +1,53 @@
+package org.eclipse.app4mc.amalthea._import.btf.model;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.app4mc.amalthea.model.ProcessEventType;
+import org.eclipse.app4mc.amalthea.model.RunnableEventType;
+import org.eclipse.emf.common.util.Enumerator;
+
+public enum BTFEntityType {
+
+	processsss(ProcessEventType.class, "T", "I"),
+	runnabless(RunnableEventType.class, "R");
+
+	private static final Map<String, BTFEntityType> name2Literal = Stream.of(values()).collect(Collectors.toMap(et -> et.entityTypeName, et -> et));
+
+	private final List<String> traceAliases;
+	private final String entityTypeName;
+
+	private BTFEntityType(Class<? extends Enumerator> eventTypeEnum, final String... traceAlias) {
+		this.traceAliases = Arrays.asList(traceAlias);
+		String entityTypeName = eventTypeEnum.getSimpleName();
+		entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase();
+		this.entityTypeName = entityTypeName;
+		
+	}
+
+	public String getName() {
+		return this.entityTypeName;
+	}
+	
+	public String getUCName() {
+		final String lcName = this.getName();
+		final String ucName = lcName.substring(0, 1).toUpperCase() + lcName.substring(1);
+		return ucName;
+	}
+	
+	public boolean isTraceAlias(final String traceAlias) {
+		return this.traceAliases.stream().anyMatch(traceAlias::equals);
+	}
+	
+	public String getTraceAliases() {
+		return this.traceAliases.stream().map(ta -> "'" + ta + "'").collect(Collectors.joining(", "));
+	}
+	
+	public static BTFEntityType getForName(String name) {
+		return name2Literal.get(name);
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFInterInstanceMetric.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFInterInstanceMetric.java
new file mode 100644
index 0000000..3cb5afc
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/model/BTFInterInstanceMetric.java
@@ -0,0 +1,37 @@
+package org.eclipse.app4mc.amalthea._import.btf.model;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Stream;
+
+import org.eclipse.app4mc.amalthea.model.ProcessEventType;
+import org.eclipse.app4mc.amalthea.model.RunnableEventType;
+import org.eclipse.emf.common.util.Enumerator;
+
+public enum BTFInterInstanceMetric {
+
+	activateToActivate(ProcessEventType.ACTIVATE, ProcessEventType.ACTIVATE),
+	startToStart(new SimpleEntry<>(ProcessEventType.START, ProcessEventType.START), new SimpleEntry<>(RunnableEventType.START, RunnableEventType.START)),
+	endToEnd(new SimpleEntry<>(ProcessEventType.TERMINATE, ProcessEventType.TERMINATE), new SimpleEntry<>(RunnableEventType.TERMINATE, RunnableEventType.TERMINATE)),
+	endToStart(new SimpleEntry<>(ProcessEventType.TERMINATE, ProcessEventType.START), new SimpleEntry<>(RunnableEventType.TERMINATE, RunnableEventType.START)),
+	slack(ProcessEventType.TERMINATE, ProcessEventType.ACTIVATE); // switch the sign of this metric to get lateness
+
+	public final Map<BTFEntityType, Entry<Enumerator, Enumerator>> entityType2FirstAndSecond;
+
+	private BTFInterInstanceMetric(final Enumerator firstInstEvent, final Enumerator secondInstEvent) {
+		this(new SimpleEntry<>(firstInstEvent, secondInstEvent));
+	}
+	
+	@SafeVarargs
+	private BTFInterInstanceMetric(final Entry<Enumerator, Enumerator>...firstAndSecondInstEvent) {
+		this.entityType2FirstAndSecond = new LinkedHashMap<>();
+		Stream.of(firstAndSecondInstEvent).forEach(entry -> {
+			String entityTypeName = entry.getKey().getClass().getSimpleName();
+			entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase();
+			entityType2FirstAndSecond.put(BTFEntityType.getForName(entityTypeName), entry);
+		});
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportPage.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportPage.java
new file mode 100644
index 0000000..38db44a
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportPage.java
@@ -0,0 +1,131 @@
+/**
+ ********************************************************************************
+ * Copyright (c) 2015 Timing-Architects Embedded Systems GmbH and others.
+ * 
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *     Timing-Architects Embedded Systems GmbH - initial API and implementation
+ ********************************************************************************
+ */
+
+package org.eclipse.app4mc.amalthea._import.btf.wizard;
+
+import java.io.File;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.WizardResourceImportPage;
+
+public class ImportPage extends WizardResourceImportPage {
+
+	private Text sourceNameField;
+
+	protected ImportPage(final IStructuredSelection selection) {
+		this("btfImportPage", selection);
+		setTitle("Import BTF");
+		this.setMessage("Select an existing BTF File to import into an ATDB");
+	}
+
+	protected ImportPage(final String name, final IStructuredSelection selection) {
+		super(name, selection);
+	}
+
+	@Override
+	protected void createSourceGroup(final Composite parent) {
+		final Composite sourceContainerGroup = new Composite(parent, SWT.NONE);
+		final GridLayout layout = new GridLayout();
+		layout.numColumns = 3;
+		sourceContainerGroup.setLayout(layout);
+		sourceContainerGroup.setFont(parent.getFont());
+		sourceContainerGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
+
+		// source label
+		final Label groupLabel = new Label(sourceContainerGroup, SWT.NONE);
+		groupLabel.setText("From directory:");
+		groupLabel.setFont(parent.getFont());
+
+		// source name entry field
+		this.sourceNameField = new Text(sourceContainerGroup, SWT.READ_ONLY | SWT.BORDER);
+		final GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
+		data.widthHint = SIZING_TEXT_FIELD_WIDTH;
+		this.sourceNameField.setLayoutData(data);
+		this.sourceNameField.setFont(parent.getFont());
+
+		// source browse button
+		final Button sourceBrowseButton = new Button(sourceContainerGroup, SWT.PUSH);
+		sourceBrowseButton.setText("Browse...");
+		sourceBrowseButton.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(final SelectionEvent e) {
+				selectFile();
+				update();
+			}
+		});
+		sourceBrowseButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
+		sourceBrowseButton.setFont(parent.getFont());
+		setButtonLayoutData(sourceBrowseButton);
+	}
+
+	@Override
+	protected ITreeContentProvider getFileProvider() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	protected ITreeContentProvider getFolderProvider() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	protected boolean determinePageCompletion() {
+		boolean result = super.determinePageCompletion();
+
+		final String path = this.sourceNameField.getText();
+		final File file = new File(path);
+		result &= file.exists();
+
+		return result;
+	}
+
+	private void selectFile() {
+		final FileDialog fileDialog = new FileDialog(getShell(), SWT.OPEN);
+		fileDialog.setText("Select file");
+		fileDialog.setFilterExtensions(new String[] { "*.btf" });
+		final String open = fileDialog.open();
+		if (open != null) {
+			this.sourceNameField.setText(open);
+			update();
+		}
+	}
+
+	protected void update() {
+		setPageComplete(determinePageCompletion());
+	}
+
+	protected String getSource() {
+		return this.sourceNameField.getText();
+	}
+
+	protected IContainer getTargetContainer() {
+		return getSpecifiedContainer();
+	}
+
+}
diff --git a/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportWizard.java b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportWizard.java
new file mode 100644
index 0000000..6b285ce
--- /dev/null
+++ b/plugins/org.eclipse.app4mc.amalthea.import.btf/src/org/eclipse/app4mc/amalthea/_import/btf/wizard/ImportWizard.java
@@ -0,0 +1,114 @@
+/**
+ ********************************************************************************
+ * Copyright (c) 2015 Timing-Architects Embedded Systems GmbH and others.
+ * 
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *     Timing-Architects Embedded Systems GmbH - initial API and implementation
+ ********************************************************************************
+ */
+
+package org.eclipse.app4mc.amalthea._import.btf.wizard;
+
+import java.util.List;
+
+import org.eclipse.app4mc.amalthea._import.btf.ImportTransformation;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.ide.IDE;
+
+public class ImportWizard extends Wizard implements IImportWizard {
+
+	private ImportPage mainPage;
+	private IStructuredSelection selection;
+
+	@Override
+	public void addPages() {
+		super.addPages();
+		this.mainPage = new ImportPage(this.selection);
+		addPage(this.mainPage);
+	}
+
+	@Override
+	public void init(final IWorkbench workbench, final IStructuredSelection selection) {
+		this.selection = selection;
+
+		final List<?> selectedResources = IDE.computeSelectedResources(selection);
+		if (!selectedResources.isEmpty()) {
+			this.selection = new StructuredSelection(selectedResources);
+		}
+
+		setWindowTitle("Import AMALTHEA Model From AMALTHEA Trace Database");
+		setNeedsProgressMonitor(true);
+	}
+
+
+	@Override
+	public boolean performFinish() {
+		final String source = this.mainPage.getSource();
+		final IContainer target = this.mainPage.getTargetContainer();
+		// get the file name of the btf
+		final int from = Math.max(source.lastIndexOf('/'), source.lastIndexOf('\\'));
+		final int to = source.lastIndexOf(".btf");
+		final String name = source.substring(from + 1, to);
+		final String atdbFile = target.getLocation() + "/" + name + ".atdb";
+
+		try {
+			final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
+
+				@Override
+				protected void execute(final IProgressMonitor progressMonitor) {
+					try {
+						final ImportTransformation transformer = new ImportTransformation(source, atdbFile);
+						transformer.run(progressMonitor);
+						// refresh workspace
+						target.refreshLocal(1, progressMonitor);
+					}
+					catch (final Exception exception) {
+						exception.printStackTrace();
+					}
+					finally {
+						progressMonitor.done();
+					}
+				}
+			};
+
+			getContainer().run(true, true, operation);
+
+		}
+		catch (final Exception exception) {
+			exception.printStackTrace();
+			return false;
+		}
+
+		// open new atdb file in viewer
+		final IProject project = target.getProject();
+		final IFile file = project.getFile(name + ".atdb");
+		final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		try {
+			IDE.openEditor(page, file);
+		}
+		catch (final PartInitException e) {
+			e.printStackTrace();
+		}
+
+		return true;
+	}
+
+}