Posts tonen met het label industrial. Alle posts tonen
Posts tonen met het label industrial. Alle posts tonen

maandag 20 januari 2014

Analyzing the Industrial SQL Connector for Mylyn with SonarQube

Last year we set up Hudson to build the Industrial SQL Connector for Mylyn, a DIY connector project to connect Mylyn to a local SQL database for which I'm a committer. This blog post I will explain how I set up static code analysis on the same project using SonarQube. Installing and setting up SonarQube is better explained elsewhere, like http://www.sonarqube.org, but then setting up a set op eclipse plugin projects to be analyzed is more specific.

Preparation:

  • Install SonarQube following instructions here.
  • Then install the Sonar plugin into Hudson using Update Center and configure it following these instructions
  • Lookup how to build the Industrial SQL Connector for Mylyn with Hudson here

Configuring the Industrial SQL Connector for Mylyn for analysis

Whether you want to analyze projects with the Maven sonar:sonar target or use the Hudson Invoke Standalone Sonar Analysis build step in both cases you need to create a sonar-project.properties file. As a matter of common sense I always put this file in the same project as the project with the maven master POM, in this case com.industrialtsi.mylyn.maven.
# required metadata
sonar.projectKey=com.industrialtsi.mylyn
sonar.projectName=Industrial SQL Connector for Mylyn
sonar.projectVersion=0.9.10-SNAPSHOT

# optional description
sonar.projectDescription=Industrial SQL Connector for Mylyn

# path to source directories (required)
#sonar.sources=src THIS IS SPECIFIED PER MODULE

# path to project binaries (optional), for example directory of Java bytecode
#sonar.binaries=target/classes THIS IS SPECIFIED PER MODULE

# optional comma-separated list of paths to libraries. Only path to JAR file is supported.
#sonar.libraries=lib/*.jar THIS IS SPECIFIED PER MODULE

# The value of the property must be the key of the language.
sonar.language=java

# modules one for each area of functionality, only plugin and fragment projects
sonar.modules=core,derby,jpa,memory,ui

# setup project base dir
core.sonar.projectBaseDir=com.industrialtsi.mylyn.core
derby.sonar.projectBaseDir=com.industrialtsi.mylyn.demo.derby
jpa.sonar.projectBaseDir=com.industrialtsi.mylyn.demo.jpa
memory.sonar.projectBaseDir=com.industrialtsi.mylyn.demo.memory
ui.sonar.projectBaseDir=com.industrialtsi.mylyn.ui

#set up source folders 
core.sonar.sources=src
derby.sonar.sources=src
jpa.sonar.sources=src
memory.sonar.sources=src
ui.sonar.sources=src

# set up binary folders
core.sonar.binaries=target/classes
derby.sonar.binaries=target/classes
jpa.sonar.binaries=target/classes
memory.sonar.binaries=target/classes
ui.sonar.binaries=target/classes

# set up libraries folders, where jars reside
core.sonar.libraries=
derby.sonar.libraries=lib/*.jar
jpa.sonar.libraries=lib/*.jar
memory.sonar.libraries=
ui.sonar.libraries=
Then we commit this file to the repository so Hudson can retrieve it.

Configuring Hudson to analyze the project

We go to the Hudson Job tab and press configure. Under Build we add a step Invoke Standalone Sonar Analysis and configure it as follows: Sonar hudson config

Building and examining the results

We make Hudson build the project and then go over to the SonarQube pages for the results, note that I have created a custom set of my favorite widgets for this: Sonarqube 1 The Technical Debt widget tell us the technical debt in days, and also a percentage split of the main problems. Lack of coverage explains half the debt, with design, comments and complexity as other issues. There are very few violations and duplications, the happy result of running with Checkstyle, Findbugs and PMD inside Eclipse during the development. I always add a Most Violated Rules widget to the project dashboard. Exposing internal representation is the most common here as the very bad package cycles. Sonarqube 2 The "Most Violated Resources" widget instantly tells me that the objects used to ferry query parameters around are the main problem area. I have a tagged sonar-project.properties file so I will be able to see progress in the future on lines of code, technical debt and documented API. Sonarqube 3 Issues are mostly Critical and Major, so need to be fixed urgently. 1% duplications is not that serious, even though 0% is best of course. Test coverage is more serious as we've seen above that lack of Test Coverage accounts for half of technical debt. This maybe because the build is not yet configured to execute tests. Sonarqube 4 The complexity stats show mainly whether design is good, a method should do one thing, a class should have one responsibility. The LCOM4 measure of 1.0/class is quite positive. Sonarqube 5 The main problem in these is the startling 40.5% of package tangle index and more than 10 cycles! This needs to be looked at with highest priority.

Action Plan

So this short exercise (total time to setup 1,5 hours) revealed quite a lot of potential problems in the code base! How then to tackle and resolve these problems?
  1. Ensure that the unit tests are executed and measured! Without unit tests we cannot begin to refactor safely.
  2. Fix the Critical Issues in the code, but only when adequately covered by unit tests
  3. Investigate and fix the Package Cycles problems, but again only when adequately covered by unit tests
  4. Fix the Major Issues in the code, but only when adequately covered by unit tests
  5. Fix the Code Duplications problems
I will report on my findings here. For unit test coverage I'm going to use Jacoco, which works well inside Eclipse using the Eclemma plugin, is preferred by SonarQube and can also be integrated with Tycho/Maven.

donderdag 22 augustus 2013

Building the Industrial SQL Connector for Mylyn with Hudson

To get early warning when changes in Eclipse, Mylyn or EclipseLink break the build of Industrial SQL Connector for Mylyn, I have set up a build on my home Hudson CI server. When you want to use this connector you can do the same following the steps below.

Prerequisites

You will need a Hudson CI server set up, follow instructions here. You will also need maven installed from here or use the integrated version.

Create a new Hudson Job

01 createjob

After pressing OK you will see:

02 jobcreated

Configure and test SVN checkout

Enter the anonymous SVN checkout url from EclipseLabs : http://svn.codespot.com/a/eclipselabs.org/industrial-mylyn/trunk/. Also configure the build triggers, now set for 30 minutes past hour on weekdays. Can probably be less, but CI is supposed to be well continuous

03 configuresvn

After saving this configuration, press Build Now

04 testbuild

05 allcheckedout

When it's done, check the Workspace. It should look like this:

06 workspaceview

Configure the Maven/Tycho build and test it.

Next step is to add building the checked out code. Industrial SQL Connector for Mylyn comes preconfigured for a Maven/Tycho build so that is easy. Add the Build Step named Invoke Maven 3

07 addmaven3build

We need some advanced options so click the Advanced button. Most important is that the root pom file is not in the root directory but in com.industrialtsi.mylyn.maven/

08 configuremaven3build

Press Build Now again.

09 testbuildagain

Build success

When all is well you should see this, Finished: SUCCESS

10 testbuildsuccess

Results are all in the Workspace, so a bit hard to find:

11 testbuildresults

Publishing artifacts

You can archive and publish the artifacts produced by Maven by configuring the build.

12 archiveresults

This produces the following Job display:

13 resultspublished

Sunshine!

14 sunshine

woensdag 25 juli 2012

Industrial SQL Connector for Mylyn updated for Eclipse 3.8/4.2 and Mylyn 3.8.0 (now version 0.9.9)

The most recent Mylyn update to version 3.8.0 broke the Industrial SQL Connecor for Mylyn, but no longer. The change was minor but illustrative: we "borrowed" the DatePicker from org.eclipse.mylyn.internal.provisional.commons.ui and as this is clearly marked internal, it was bound to break at some point. Luckily the Mylyn developers moved this DatePicker out of internal API so everybody can use it. It is now part of the org.eclipse.mylyn.commons.workbench Bundle. If you want to use for Mylyn before 3.8.0 you should check out code from SVN tag /tags/mylyn-3.7.0 The updated code is in /trunk/ I also update the info at Eclipse Marketplace and the code at EclipseLabs. The Industrial SQL Connector for Mylyn allows you to set up a Mylyn connection to any accessible database with Task related information. A default Query UI for some very basic task settings is also provided. You define a set of SQL queries, and package these with some configuration in a fragment, the connector does the rest. You can use either EclipseLink/JPA technology with annotations or Ibatis 2.3.0 with configuration in XML files. Screen Shot 2012 07 25 at 22 30 56 Example projects are included and described elsewhere on this blog. The compiled code can also be installed from the update site

zaterdag 29 mei 2010

Bug 184532 RESOLVED: Industrial Connector moved to Eclipselabs


History

The Mylyn project has grown tremendously and taken on new directions since bug 184532 [connector] Generic SQL connector was opened in 2007. Widescale adoption and praise for Mylyn and the foundation of Tasktop was followed by the release of many commercial connectors.
As Mik has pointed out elsewhere, the Mylyn dev team simply does not have the resources to maintain the many contributions offered, one of which was this SQL connector.
This is the only way for the Mylyn project to stay in innovation mode, stay out of maintenance mode! We understand and respect that decision as we too will benefit from that innovation.

The Industrial SQL Connector for Mylyn does have an active though not very visible user community as it is the basis of the Mylyn connector of the commercial software change management product of Remain Software.

As can be seen from the entries in bug 184532 mentioned above also some people have used the Industrial SQL Connector to create connections to their in-house SQL based systems.

Move to Eclipselabs.org

For this reason we have decided to take the opportunity to join the newly formed Eclipselabs.org with code hosting at Google code, and no longer actively pursue becoming part of mylyn core. There we will have our own dedicated Wiki, issue tracker, SVN repository and update site, so we no longer have to free ride on the eclipse.org infrastucture.
As a consequence the projects and packages will be renamed to get rid of the org.eclipse.mylyn.* prefix and revert back to com.industrialtsi.mylyn.*, but will keep the EPL as license.

The new location for the project and source code is here:
http://code.google.com/a/eclipselabs.org/p/industrial-mylyn/

We will be updating the Wiki and blog in the days to come. We fixed some more bugs, upgraded the version to 0.9.6 and offer a preliminary update site here:
http://svn.codespot.com/a/eclipselabs.org/industrial-mylyn/trunk/com.industrialtsi.mylyn.site/

We are also present in the Eclipse Marketplace to be ready for Helios release here:
http://marketplace.eclipse.org/content/industrial-sql-connector-mylyn.

The above is an edited and more elaborate version of the closing comment on bug 184532.

zondag 25 oktober 2009

DIY Mylyn Twitter connector

Connecting Mylyn to SQL databases is easy using the Industrial SQL Connector for Mylyn, but you can also connect to something else by implementing or extending the IPersistor interface.
In this blog I describe how to quickly create a basic connector that will allow you follow one or more Twitter feeds right in the Mylyn Task List. Twitter is used to send out notifications by an ever increasing range of hardware or processes:
  • Wim Jongman tweeted about connecting an AS/400 or iSeries to Twitter to notify on jobs>>.
  • Kim Moir added twitter as a way of build notifications for the Equinox team using Hudson twitter plugin >>
  • And there are probably many more...

We are going to create a read-only connector to start with, as these build processes and hardware will not read any responses to their tweets or please their egos by following mentions!

Initial Setup

Install the Industrial SQL Connector for Mylyn from the update site (detailed instructions) or extract the source from SVN.
2011 02 22 Updated links to EclipseLabs update site

Create fragment project

Create a fragment project selecting the org.eclipse.mylyn.industrial.core plugin as host..
Create a lib folder and a run-configs folder. (I need to create a template wizard for this soon!)

Select twitter java library

I looked at the twitter API wiki and chose for Twitter4J as various source considered it most mature. Download it and install it in the fragment's lib folder. There is no need to export any packages!

Create Persistor extension

In the extensions tab of the fragment.xml create an extension to extension point org.eclipse.mylyn.industrial.core.persistor and create a new persistor-config.

Then set the repository attributes to false except for can-create-task-from-key and can-query-repository

Then set all the task attributes to read-only.

Code the Persistor extension using the library

Now we click on the persistor hyperlink to create the Java class, we extend the class PersistorAdapter that basicaly logs all calls and returns sensible defaults.
To query and show tasks we need to implement fetchTask(...), findTasks(...), and to make querying easier also findlegalOwners(...).
package org.eclipse.mylyn.industrial.twitter.persistor;
[...]
public class TwitterPersistor extends PersistorAdapter {

public final static String ID = "org.eclipse.mylyn.industrial.twitter"; //$NON-NLS-1$

private User user;

private Twitter twitter;

public TwitterPersistor() {
}

/**
* @return the twitter, initialize if needed
*/
public Twitter getTwitter(TaskRepository repository) {
if (null == twitter) {
AuthenticationCredentials credentials = repository
.getCredentials(AuthenticationType.REPOSITORY);
String twitterPassword = credentials.getPassword();
String twitterID = credentials.getUserName();
twitter = new Twitter(twitterID, twitterPassword);
}
return twitter;
}

@Override
public IndustrialTask fetchTask(TaskRepository repository, String... taskId)
throws SQLException, CoreException {
Twitter t = getTwitter(repository);

long id = Long.parseLong(taskId[0]);

try {
twitter4j.Status result = t.showStatus(id);
IndustrialTask tweet = new IndustrialTask(repository.getUrl(),
taskId[0], result.getText());

tweet.setOwner(result.getUser().getName());
tweet.setCreationDate(result.getCreatedAt());
tweet.setNotes(result.getText());
return tweet;
} catch (TwitterException e) {
IStatus status = CoreLogger.createStatus(IStatus.ERROR, e);
throw new CoreException(status);
}
}

@Override
public List<String> getLegalOwners(TaskRepository repository)
throws SQLException, CoreException {
Twitter t = getTwitter(repository);

List<String> result = new ArrayList<String>();
List<User> friends;
try {
friends = t.getFriendsStatuses();
for (User friend : friends) {
result.add(friend.getName());
}
return result;
} catch (TwitterException e) {
IStatus status = CoreLogger.createStatus(IStatus.ERROR, e);
throw new CoreException(status);
}
}

@Override
public List<String> findTasks(TaskRepository repository,
IndustrialQueryParams criteria) throws SQLException, CoreException {
Twitter t = getTwitter(repository);

List<String> result = new ArrayList<String>();
try {
for (String user : criteria.getOwner()) {
List<twitter4j.Status> timeline;
timeline = t.getUserTimeline(user);
for (twitter4j.Status s : timeline) {
result.add(Long.toString(s.getId()));
}
}
return result;
} catch (TwitterException e) {
IStatus status = CoreLogger.createStatus(IStatus.ERROR, e);
throw new CoreException(status);
}
}

@Override
public boolean validate(TaskRepository repository) throws SQLException,
CoreException {
return null != getTwitter(repository);
}

@Override
public boolean isAuthenticated(TaskRepository repository)
throws SQLException, CoreException {

try {
user = getTwitter(repository).verifyCredentials();
return true;
} catch (TwitterException e) {
Status status = new Status(IStatus.ERROR, TwitterPersistor.ID,
"Cannot validate Twitter"); //$NON-NLS-1$
throw new CoreException(status);
}
}
}

We add the methods isAuthenticated(...) and validate(...) but both can just default to returning true when just statrting your development.

Now Run and we're Done!


OK the we run the whole project and create a new twitter repository, using your own name and password:

It will even check whether we entered our password correctly when we press the Validate button and call validate(...)

We can now do a simple query on the list of tweeters we are following using a form based query.

And presto, we have the tweeted AS/400 messages in our Mylyn Tasklist!

Conclusion


By parameterizing the creation of Mylyn connectors, the Industrial SQL Connector for Mylyn makes creating a quick and dirty connector to almost anything very, very easy. Creating this connector took me a little more than 2 hours, almost less than creating this blog entry.
Source code can be downloaded here.

donderdag 17 september 2009

Industrial SQL Connector and Eventum: UNION queries

After playing around with Eventum some more as a result of looking into the Mylyn [connector] Eventum request I noticed that Eventum supports a very elaborate system of comments: Internal Notes, Phone calls, Drafts, emails and attachments in addition to the issue status history we included earlier.
Our question for today is whether we can support this diversity with the simplified task model provided with the Industrial SQL Connector?

MySQL UNION queries

MySQL provides the UNION statement to merge the results of two or more SELECT queries. So we try the following edit of CommentMapEventum.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!--
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com
-->
<sqlMap namespace="Comments">
...
<select id="getForKey" resultClass="ibatisComment">
(SELECT
his_created_date as groupKey,
usr_email as author,
usr_full_name as authorName,
his_created_date as date,
his_summary as text
FROM eventum_issue_history
INNER JOIN eventum_user ON his_usr_id = usr_id
WHERE his_iss_id = #value#
ORDER BY his_id)
UNION
(SELECT
not_created_date as groupKey,
usr_email as author,
usr_full_name as authorName,
not_created_date as date,
not_note as text
FROM eventum_note
INNER JOIN eventum_user ON not_usr_id = usr_id
WHERE not_iss_id = #value#
ORDER BY not_id)
</select>
...
</sqlMap>

Results from modified query

We run again and look at an issue with an internal note attached:

We see the internal notes text merged with the history. When we use a CONCAT() statement we can even prefix different parts with different makeup or create more elaborate text bits.

Conclusion


If you know how to write SQL queries you can do fairly complex stuff with the Industrial SQL Connector.
So go ahead and give it a try yourself! Installation instructions are provided here.

dinsdag 15 september 2009

Industrial SQL connector and Eventum: adding attachments

Last time we covered Eventum task and comments, this time we'll make the attachments show up in Mylyn.

Eventum attachments


We create an attachment in our Eventum test installation and see what happens. Two tables are involved in the handling of attachments: eventum_issue_attachment containing the meta information like date created and creator, and eventum_issue_attachment_file containing actual data, filename, mime type and filesize.

Modifying the repository-config settings


We must edit fragment.xml and set the can-get-attachments property to true.

Creating the attachment data query


To return the attachment meta-data we must edit CommentsMapEventum.xml and set the getAttachmentForKey query as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!--
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com
-->
<sqlMap namespace="Comments">
...
<select id="getAttachmentForKey" resultClass="ibatisAttachment">
<!-- meta data only, return the blob data separately -->
SELECT
usr_email as author,
iaf_filetype as ctype,
iat_created_date as date,
iat_description as description,
iaf_filename as filename,
iaf_id as id,
iaf_filesize as size,
iat_iss_id as taskId,
'' as url
FROM eventum_issue_attachment
INNER JOIN eventum_user ON iat_usr_id = usr_id
INNER JOIN eventum_issue_attachment_file ON iat_id = iaf_iat_id
WHERE iat_iss_id = #value#
</select>
...
</sqlMap>

Creating the attachment BLOB query


To return the attachment binary BLOB we must edit CommentsMapEventum.xml and set the getAttachmentDataForKey query as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!--
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com
-->
<sqlMap namespace="Comments">
...
<resultMap id="attachmentDataMap" class="ibatisAttachment">
<result property="blob" column="iaf_file" jdbcType="BLOB" javaType="[B"/>
</resultMap>

<select id="getAttachmentDataForKey" resultMap="attachmentDataMap">
<!-- return the blob data -->
SELECT iaf_file
FROM eventum_issue_attachment_file
WHERE iaf_id = #value#
</select>
...
</sqlMap>

The attachment displays nicely but...


We can see the attachments in the Task Editor, an image uploaded using the web interface, but when we right-click we see several actions that do not work.


Open With Browser will not work, as the Eventum attachments are stored in a database, so they have no web url and cannot be shown in the browser. This is reported under bug 249021. This action should be dimmed when no URL is present.

Open With/Default EditorThis functionality was recently added, but does not take into account the case where no URL is present. This is in the works under bug 220314 and should be dimmed when no URL is present.

Make Local Copy and Open in Browser this is Industrial Connector functionality present to remedy the problems above, but is not a really neat solution.

maandag 7 september 2009

Industrial SQL Connector and Eventum

When looking at the Mylyn connector Most Wanted List you'll see many issue tracker that do not have a dedicated connector to the Mylyn Eclipse Task based UI.

Many of these are backed by databases to store all the complex relations and workflow. In the next several blogs I'm going to demonstrate how easy it is to connect Mylyn to any database backed issue tracker using the Industrial SQL Connector.
For the example I will be using Eventum, created and used by MySQL, number 4 on the list. It is also OSS, so we can easily get it to play around with.
This will not be a full fledged connector, but a quick start to get the task change notification directly from email into Eclipse as first step in making you more productive.

Install Industrial SQL Connector


This connector can be installed from http://svn.codespot.com/a/eclipselabs.org/industrial-mylyn/trunk/com.industrialtsi.mylyn.site/
Note Images display Pre EclipseLabs update site

Download empty MySQL connector Fragment


You can download a ready made empty MySQL connector Fragment as described here and unzip it and rename some files, so we get this structure:

I want to make this easier but need code from PDE, please vote for bug 288547: Add a NewFragmentFromTemplateWizard with API to make Fragments from templates

Install Eventum 2.2


Install this on you local machine following instructions provided here, so you can inspect the database tables, create and test the queries.
Then when you are completely satisfied that it works, do you change and connect to the production database!
Once the default install is completed use a database inspection tool like phpMyAdmin or soemthing else to familiarize yourself with the database structure. Luckily the Eventum designers used a very consistent naming scheme for TABLES and COLUMNS!

Once completed you can log into the system and start creating some initial users, projects and issues.


While creating a user, a project and a test issue in the web interface, make notes of what backend database tables change and get filled, because the Industrial SQL Connector is all about mapping database tables to task fields. Databases are usually constructed with record ID's for the machine and record names or titles for us, the users. As Mylyn is about making us more productive, we will as a matter of policy retrieve the human-readable formats from the database and map those back into records using JOIN statements. The preliminary mapping is as follows:
Task SideEventum Table
Taskseventum_issue
Productseventum_project
Issue Statuseventum_status, eventum_resolution
Issue Priorityeventum_project_priority
Commentseventum_issue_history
Peopleeventum_user, eventum_issue_user

Creating the Connector: step 1 creating extension


Open the fragment.xml and create extension org.eclipse.mylyn.industrial.core.persistor and create a persistor-config, add an ibatis-config. Fill in the fields as below:

Creating the Connector: step 2 retrieving repository elements


Edit the file maps/eventum-direct-db/RepositoryMapEventum.xml as follows.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!-- 
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com

--> 
<sqlMap namespace="Repository">
<!--
Legal issue owners and other legal values for fields are taken here
from DISTINCT values in the database. An alternative would be a
SELECT from any table containing legal users.
-->
<!-- return a list of legal issue owners. -->
<select id="legalOwners" resultClass="string">
SELECT DISTINCT usr_full_name FROM eventum_user
</select>
<!-- return a list of legal products. -->
<select id="legalProducts" resultClass="string">
SELECT DISTINCT prj_title FROM eventum_project
</select>
<!-- return a list of legal issue status values. -->
<select id="legalIssueStatus" resultClass="string">
SELECT DISTINCT sta_title FROM eventum_status
</select>
<!-- return a legal list of priority values.
Note that in Mylyn these all need to be mapped to one of
"P1", "P2", "P3", "P4" or "P5". -->
<select id="legalPriority" resultClass="string">
SELECT DISTINCT concat('P',pri_rank) FROM eventum_project_priority
</select>
<!-- this query will be executed when pressing the Validate Connection in
the Repository Settings dialog -->
<statement id="validate" resultClass="boolean">SELECT TRUE </statement>
<!-- this query will be executed when pressing the Validate Connection in
the Repository Settings dialog -->
<statement id="authenticate" resultClass="boolean">
SELECT TRUE
</statement>
<!-- This query will be executed when validation fails and the repository
can be initialized or updated based on version (like local Derby) -->
<statement id="initialize" resultClass="string" parameterClass="string">
$value$
</statement>
</sqlMap>

This will give us a nice prefilled dialog in of the Form Based Query:

Creating the Connector: step 3 mapping the task


Open the file maps/eventum-direct-db/TaskMapEventum.xml and locate the query getForKey. This query retrieves all mappable issue attributes give an issue ID to use as key.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!-- 
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com
--> 
<sqlMap namespace="Tasks">

<select id="getForKey" resultClass="ibatisTask">
SELECT
iss_id as taskId,
concat('P',pri_rank) AS priority,
usr_full_name AS owner,
iss_summary AS summary,
iss_description as notes,
prj_title AS product,
sta_title AS issueStatus,
iss_created_date AS creationDate,
iss_closed_date AS completionDateDate,
iss_expected_resolution_date AS dueDateDate
FROM eventum_issue
INNER JOIN eventum_issue_user ON isu_iss_id = iss_id 
INNER JOIN eventum_user ON isu_usr_id = usr_id 
INNER JOIN eventum_project ON iss_prj_id = prj_id 
INNER JOIN eventum_status ON iss_sta_id = sta_id 
INNER JOIN eventum_project_priority ON iss_pri_id = pri_id 
WHERE iss_id LIKE #value#
</select>
[...]
</sqlMap>

Creating the Connector: step 4 adding dynamic search


We also need to edit the statement in searchForKey for the Form Based Query to make its selection:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!-- 
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com

--> 
<sqlMap namespace="Tasks">
[...]
<select id="searchForKey" parameterClass="ibatisCriteria" resultClass="string">
SELECT DISTINCT iss_id as taskId FROM eventum_issue
<dynamic> 
<isNotEmpty property="product">
INNER JOIN eventum_project  ON iss_prj_id = prj_id
</isNotEmpty>
<isNotEmpty property="priority">
INNER JOIN eventum_project_priority ON iss_pri_id = pri_id
</isNotEmpty>
<isNotEmpty property="issueStatus">
INNER JOIN eventum_status  ON iss_sta_id = sta_id
</isNotEmpty>
</dynamic>
<dynamic prepend="WHERE">
<isNotEmpty property="summary" prepend="AND"
removeFirstPrepend="true"> iss_summary LIKE '%$summary$%'
</isNotEmpty>
<isNotEmpty property="creationDateBefore" prepend="AND"
removeFirstPrepend="true"> iss_created_date <= #creationDateBefore#
</isNotEmpty>
<isNotEmpty property="creationDateAfter" prepend="AND"
removeFirstPrepend="true"> iss_created_date gt;= #creationDateBefore#
</isNotEmpty>
<isNotEmpty property="product">
<iterate property="product" conjunction="OR" open="(" close=")"
prepend="AND" removeFirstPrepend="true">
prj_title = #product[]#</iterate>
</isNotEmpty>
<isNotEmpty property="priority">
<iterate property="priority" conjunction="OR" open="(" close=")"
prepend="AND" removeFirstPrepend="true">
pri_rank = right(#priority[]#,1)</iterate>
</isNotEmpty>
<isNotEmpty property="issueStatus">
<iterate property="issueStatus" conjunction="OR" open="(" close=")"
prepend="AND" removeFirstPrepend="true">
sta_title = #issueStatus[]# </iterate>
</isNotEmpty>
</dynamic>        
</select>
[...]
</sqlMap>

Using the <dynamic> tag in the SqlMaps query language, you can specify fully dynamic queries, that will do this:

Creating the Connector: step 5 adding comments


When we have the basic task and attributes, we will not notice all activity that happens around a task. A Task or Issue usually has some sort of history associated with it, and this can be done by editing the file maps/eventum-direct-db/CommentsMapEventum.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!-- 
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com

--> 
<sqlMap namespace="Comments">
[...]
<!--
groupKey use : when you want Mylyn to concatenate strings in different
records into one comment you can force that to happen by giving these
strings the same groupKey.

Leaving the the groupKey set to null, will concatenate all records into
one Mylyn comment. This is counterintuitive!!
-->
<select id="getForKey"  resultClass="ibatisComment">
SELECT
his_created_date as groupKey,
usr_email as author,
usr_full_name as authorName,
his_created_date as date,
his_summary as text
FROM eventum_issue_history
INNER JOIN eventum_user ON his_usr_id = usr_id
WHERE his_iss_id = #value#
ORDER BY his_id
</select>
[...]
</sqlMap>
Note the use of groupKey in the statement. This construct will force all comments from the same date to be listed into one comment. Eventum issue edits result in multiple items being entered into the history using the same timestamp. Using groupKey allows you to define or alter the grouping of comments.

Creating the Connector: step 6 adding additional attributes


Sometimes we have additional attributes that can be mapped to the Mylyn common attributes listed in TaskAttributeMapper.java. Open the file maps/eventum-direct-db/TaskMapEventum.xml and go to query additionalForKey.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<!-- 
licensed under ECL, to connect Mylyn to SQL databases
Copyright 2009 Maarten Meijer, all right reserved.
http://eclipsophy.blogger.com

--> 
<sqlMap namespace="Tasks">
[...]
<!--
Keys for TaskData attributes used by Mylyn in the RepositoryTaskData structure

listed in file /org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttributeMapper.java

There is a problem in ibatis where dot notation fields returned in a Map are parsed as bean properties.
-->
<select id="additionalForKey" resultClass="java.util.HashMap">
SELECT
res_title as task_common_resolution,
usr_full_name as task_common_user_reporter
FROM eventum_issue
INNER JOIN eventum_resolution ON res_id = iss_res_id 
INNER JOIN eventum_user ON usr_id = iss_usr_id 
WHERE iss_id LIKE #value#
</select>
[...]
</sqlMap>

Conclusion


By following the simple steps outlined above, it is very easy to create a read-only connector to any database backed issue tracker. The Tasks in Mylyn are filled using a direct mapping of database columns to task elements and is not very complicated. Not a single line of Java code was needed! There is a usable UI to queries, and the results are displayed in the Task Editor, allowing a local context to be attached to it.

Connecting to database is easy when it is on the same LAN, slightly more involved when it is remote. My experience using a SSH tunnels using Putty (under Windows) or similar is that it can make a relatively secure connection easy to setup.
The connector fragment including source project can be downloaded in a ZIP from here.

donderdag 3 september 2009

Industrial SQL Connector versatility

I just created a quick solution for https://bugs.eclipse.org/150174 Eventum Mylyn connector using the Industrial SQL Mylyn connector toolkit in under 60 minutes! Screenshots @ bug, details to follow here.





A ZIP with basic code is available here