maintain library project for Maven and Eclipse RCP/ OSGi in the same repository

If you are working both in the Maven and the Eclipse RCP/ OSGi universe, you might find it quite frustrating that these two worlds cooperate so poorly. In order to use the same library in both worlds, a lot of error-prone copy-and-paste is needed, at least if you would like to use this project in a Maven and Maven Tycho build.

In principle, there is not much that is different for a Maven artifact and an Eclipse RCP/ OSGi Plug-in:
In an Eclipse RCP/ OSGi Plug-in you just need an additional META-INF/MANIFEST.MF and build.properties file. The problem comes with the Maven pom file, which looks completely different for standard Maven and Maven Tycho. Luckily, you can specify the name of the pom file when invoking Maven:

Therefore, you can just maintain two pom files and with only few limitations, it is possible to maintain a library that can be used in a standard Maven build and in a Maven Tycho build within the same repository:

  1. Modify your .gitignore so that it contains the following lines:
    bin
    .project
    .settings
    .classpath
    
    We don’t want to have any Eclipse project configuration information in the project, since we want to be able to import it both as ‘Maven project’ and ‘Eclipse/ OSGi project’.
  2. Remove all files from the git index that match the pattern above.
    • If your project is a Maven project, right-click on the project and select ‘Configure -> Convert to Plug-in project’. This will create the META-INF/MANIFEST.MF and build.properties files.
    • If your project is a Plug-in project, right-click on the project and select ‘Configure -> Convert to Maven project’. This will create the pom.xml file.
    These steps are optional and only needed if you are missing either pom.xml or META-INF/MANIFEST.MF and build.properties .
  3. Create the Tycho pom file, name it e.g. pom-tycho.xml. It’s content should look like this:
  4. Commit all changes and delete the project from your workspace.
  5. Import the project using the ‘Import Existing Maven Project’ or ‘Checkout Maven Project from scm’ wizard. To use the project as an Eclipse RCP/ OSGi Plug-in project, disable it’s Maven nature via ‘Maven -> disable Maven nature’.
  6. Done!
Note: You manually need to keep in sync the version strings in pom.xml, META-INF/MANIFEST.MF and pom-tycho.xml! E.g. after running a Maven release, you need to adapt the version numbers in META-INF/MANIFEST.MF and pom-tycho.xml so that they match the automatically changed version strings in pom.xml.
Also note that you cannot use a Bundle Activator in this project. If you need one, just create another Eclipse-RCP Plug-in that depends on your library and contains a Bundle Activator.

Troubleshooting: After importing as Maven project or converting to Maven project, you might run into build-path problems. Try to resolve using ‘right-click on project -> Maven -> Update Project..’ And/ or fix the Java Build Path of the project (Standard Eclipse source folder is src, in Maven it is src/main/java). java-build-path

OrientDB Document API best practices

OrientDB is an open source NoSQL Database Managment System, which supports multiple models of operation:
  1. Document Model,
  2. Graph Model
  3. and
  4. Object Model.
We will write here about the Document Model. It is the most low-level of the three models and and can provide great performance if no graph or object model is needed. Nevertheless, using a document-based database requires different programming patterns than the ones you know already from the world of object-oriented programming. We will try to compose some best-practices and programming patterns here to guide you when working with document-based database systems in general and the usage of the OrientDB Document API in particular.

  1. Performance and Threading
    ODocument is not thread save. It is not intended to be accessed by multiple threads at the same time. Accessing the db using multiple instances of ODatabaseDocumentTx nevertheless is thread save.

    Anti-Pattern

    Pattern
    Explanations
    Note that documentDatabase itself is not used. ODocument accesses the document database via a thread-local, static instance of ODatabaseDocumentInternal. Consistently, it is required to set this thread-local instance in each thread that is running on the ODocument class.
  2. To be continued

Install Oracle Java 8

ClassCastException for Interface and implementing class or for same class

  • Problem: In a multimodular project, where multiple modules use the same libraries, you run into ClassCastExceptions for the same class or for interface and correctly implementing class.
  • Solution: Do not add required libraries to each module separately. Instead, wrap all libraries into a dedicated module from which you reexport all packages.
  • Additional information: Each module uses it’s own classloader. During runtime, the identity of a class is not only defined by its fully qualified classname but by it’s class loader as well, which is why “identical” classes loaded by different class loaders cause ClassCastExceptions.

PropertyChangeSupport vs. SwingPropertyChangeSupport

PropertyChangeSupport fires events on the current thead. SwingPropertyChangeSupport can fire events as well on the EDT (Event Dispatch Thread).

Install any jar manually into Maven repository

mvn install:install-file -DlocalRepositoryPath=local-repo -DcreateChecksum=true -Dpackaging=jar -Dfile=[your-jar] -DgroupId=[...] -DartifactId=[...] -Dversion=[...]
local-repo can be an additional repository (inside and exclusive) for a specific project or can be the default repository, which is ~/.m2/repository.

query uniprot via REST web service using Java

package com.silicosciences.ws.rest.client.embl;
import java.io.InputStream;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import net.sf.kerner.utils.collections.trasformer.ToString;
public class RestClientDBQuery {
	public static void main(String[] args) {
		final String dbName = "swissprot"; // Database name (e.g. UniProtKB)
		final String id = "HBA_HUMAN"; // Entry identifier, name or accession
		final String format = "uniprot"; // Data format
		final String urlBase = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/";
		final String urlFinal = urlBase + dbName + "/" + id + "/" + format;
		System.out.println("URL is: " + urlFinal);
		CloseableHttpResponse response;
		final CloseableHttpClient client = HttpClients.createDefault();
		try {
			// Create a HTTP GET request
			final HttpGet method = new HttpGet(urlFinal);
			response = client.execute(method);
			final HttpEntity entity = response.getEntity();
			final InputStream stream = entity.getContent();
			final List lines = IOUtils.readLines(stream);
			System.out.println("Received " + lines.size() + " lines");
			System.out.println(new ToString().toString(lines));
			EntityUtils.consume(entity);
		} catch (final Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

pom.xml:

	4.0.0
	com.silicosciences.ws
	rest.client
	0.0.1-SNAPSHOT
	REST Client
	
		
			org.apache.httpcomponents
			httpclient
			4.5.1
		
		
			commons-io
			commons-io
			2.4
		
		
			net.sf.kerner-utils-collections
			kerner-utils-collections
			1.1.2-SNAPSHOT
		
	

release jar’s using maven that can be used as OSGi bundles as well

Once
  1. Configure your jar plugin to include an OSGi compatible MANIFEST.MF file:
    
    
    
    org.codehaus.mojo
    build-helper-maven-plugin
    1.9.1
    
    
    set-osgi-version
    verify
    
    parse-version
    
    
    
    regex-property
    verify
    
    regex-property
    
    
    hans
    ${parsedVersion.osgiVersion}
    SNAPSHOT
    qualifier
    false
    
    
    
    
    
    org.apache.maven.plugins
    maven-jar-plugin
    2.3.2
    
    
    
    ${parsedVersion.osgiVersion}
    ${project.description}
    ${project.version}
    
    META-INF/MANIFEST.MF
    
    
    
    
    org.apache.maven.plugins
    maven-source-plugin
    2.4
    
    
    attach-sources
    verify
    
    jar
    
    
    
    
    
    
    2
    ${project.name}
    ${project.description}
    ${project.groupId}.${project.artifactId}.source
    ${project.organization.name}
    ${hans}
    ${project.groupId}.${project.artifactId};version="${hans}";roots:="."
    
    
    
    
    
    
Every release
  1. Commit all your changes.
  2. Adapt pom.xml to match the new version plus -SNAPSHOT string.
  3. Adapt MANIFEST.MF to match the new version omitting -SNAPSHOT string or .qualifer string respectively. Example:
    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-RequiredExecutionEnvironment: J2SE-1.5
    [..]
    Bundle-Version: 1.0.0
    [..]
  4. Make sure all your exported packages match the new version. Example:
    [..]
    Bundle-Version: 1.0.0
    Export-Package: net.sf.my.tools;version="1.0.0",
     net.sf.my.tools.async;version="1.0.0",
     net.sf.my.tools.comparator;version="1.0.0",
    Import-Package: org.junit;resolution:=optional,
     org.slf4j
    
    Again no .qualifier string!
  5. Perform your release as usual:
    user@client:~$ mvn clean release-prepare
    user@client:~$ mvn release-perform
    
  6. During the release, Maven will update the artifact version to the next iteration, e.g. 1.0.1-SNAPSHOT. This is done automatically but affects only the pom.xml. You have to adapt MANIFEST.MF manually to reflect the new version. This time, take over the Maven version string as given (replacing -SNAPSHOT with .qualifer). Example:
    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-RequiredExecutionEnvironment: J2SE-1.5
    [..]
    Bundle-Version: 1.0.1.qualifier
    [..]
  7. Again, make sure all your exported packages match the new version. Example:
    [..]
    Bundle-Version: 1.0.0
    Export-Package: net.sf.my.tools;version="1.0.1.qualifier",
     net.sf.my.tools.async;version="1.0.1.qualifier",
     net.sf.my.tools.comparator;version="1.0.1.qualifier",
    Import-Package: org.junit;resolution:=optional,
     org.slf4j
    
    This time include the .qualifier string.
  8. Done!
Known bugs and limitations:
  1. When you add this p2-repository to an Eclipse Target Platform, Eclipse will not correctly distinguish between artifact and source artifact.
  2. It is not very convenient to adapt the OSGi versions manually before and after each release. A shell script or Maven plugin may help here.