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
+ ("Content"). Unless otherwise indicated below, the Content
+ is provided to you under the terms and conditions of the Eclipse
+ Public License Version 2.0 ("EPL"). 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, "Program" 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
+ ("Redistributor") 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 (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION
+ OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+ </p>
+ <h2 id="definitions">1. DEFINITIONS</h2>
+ <p>“Contribution” 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
+ “originates” from a Contributor if it was added to the Program by such
+ Contributor itself or anyone acting on such Contributor's behalf.
+ Contributions do not include changes or additions to the Program that
+ are not Modified Works.
+ </li>
+ </ul>
+ <p>“Contributor” means any person or entity that Distributes the Program.</p>
+ <p>“Licensed Patents” 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>“Program” means the Contributions Distributed in accordance with this
+ Agreement.
+ </p>
+ <p>“Recipient” means anyone who receives the Program under this Agreement
+ or any Secondary License (as applicable), including Contributors.
+ </p>
+ <p>“Derivative Works” 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>“Modified Works” 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>“Distribute” means the acts of a) distributing or b) making available
+ in any manner that enables the transfer of a copy.
+ </p>
+ <p>“Source Code” 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>“Secondary License” 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'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'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' 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
+ (‘notices’) 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 (“Commercial Contributor”)
+ hereby agrees to defend and indemnify every other Contributor
+ (“Indemnified Contributor”) against any losses, damages and costs
+ (collectively “Losses”) 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'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 “AS IS” 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's patent(s), then such Recipient's rights granted
+ under Section 2(b) shall terminate as of the date such litigation is filed.
+ </p>
+ <p>All Recipient'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's rights under this Agreement
+ terminate, Recipient agrees to cease use and distribution of the Program
+ as soon as reasonably practicable. However, Recipient'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 – Form of Secondary Licenses Notice</h2>
+ <p>“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}.”
+ </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;
+ }
+
+}