About

Jadira is the home for Sousan and Chris Pheby's open source projects. These are reusable open source Java modules that provide first class solutions using the most effective current JEE technologies.

Search
Tag Cloud
...
Login
Saturday
Apr192014

Spring, Hibernate and JTA - A Better Integration

The Problem Space

A perennial issue I have frequently encountered (and solved) lies in the integration of Spring and Hibernate's transaction management.

Both Spring and Hibernate provide distinct transaction manager lookup strategies. In Spring, you'll typically configure a transaction manager by declaring a Spring managed bean that implements the PlatformTransactionManager interface provided by Spring. Included with Spring are a variety of implementations for the most common application servers as well as some non-JTA implementations, that are suitable for testing or limited (single-resource) production uses.

Meanwhile, Hibernate provides its abstraction - the JtaPlatform, the implementing type for which must be configured as part of the Hibernate EntityManager or Session configuration.

The result is that for each deployment environment - unit test, and any planned production container - a separate transaction manager and entity manager must be configured. As an additional problem, if you want to use local transactions in unit tests, the type (JTA or RESOURCE_LOCAL) must be changed in the persistence.xml.

All of this means, that delivery of portable components is fraught with complexity and configuration hell.

A Simplification

A huge simplification could be gained if Hibernate could reference whatever transaction manager you configured in Spring. The Hibernate API requires the capability to access the JTA Transaction Manager, and Spring can provide this - assuming you configured a JtaTransactionManager or one ifs subclasses, which expose both getTransactionManager and getUserTransaction methods.

Assuming we could provide to Hibernate the JtaTransactionManager, we can write an implementation of AbstractJtaPlatform which looks up the resources we need:

    @Override
    protected TransactionManager locateTransactionManager() {
        return transactionManager.getTransactionManager();
    }

    @Override
    protected UserTransaction locateUserTransaction() {
        return transactionManager.getUserTransaction();
    }

Customising LocalContainerEntityManagerFactoryBean

Providing the TransactionManager to this class is tricky. That is because its lifecycle and instantiation is managed by Hibernate, not by Spring. However, assuming you are using Spring to bootstrap the Hibernate Session or EntityManager, the solution is relatively straightforward. I'll discuss the EntityManager case - the Session solution is essentially the same.

It becomes necessary to subclass LocalContainerEntityManagerFactoryBean, and include on the subclass a setter allowing injection of the Spring TransactionManager. Then, the createNativeEntityManagerFactory() method needs overriding:

public class HibernateEntityManagerFactoryBean extends LocalContainerEntityManagerFactoryBean {

    private JtaTransactionManager transactionManager;

    private static final ThreadLocal<JtaTransactionManager> configurationTransactionManagerHolder = new ThreadLocal<JtaTransactionManager>();

    static JtaTransactionManager getConfigurationTransactionManager() {
        return configurationTransactionManagerHolder.get();
    }

    @Override
    protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {

        if (this.transactionManager != null) {
            configurationTransactionManagerHolder.set(this.transactionManager);
        }

        try {
            return super.createNativeEntityManagerFactory();
        } finally {

            if (this.transactionManager != null) {
                configurationTransactionManagerHolder.set(null);
            }
        }
    }

    /**
     * Associate a transaction manager with this session
     * @param transactionManager The {@link JtaTransactionManager}
     */
    public void setTransactionManager(JtaTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }
}

As Hibernate is bootstrapped, the JtaTransactionManager reference is stored in a static ThreadLocal. We use ThreadLocal to guard against the possibility of Spring being bootstrapped in other threads within the same classloader - at the same time (e.g. within an application server). This ThreadLocal can then be accessed via our JtaPlatform implementation as it initialises. Here's the full code for that:

public class LocalTransactionManagerPlatform extends AbstractJtaPlatform implements JtaPlatform {

    private static final long serialVersionUID = 8676743510117311360L;

    private volatile JtaTransactionManager transactionManager;

    public LocalTransactionManagerPlatform() {

        JtaTransactionManager tm = HibernateEntityManagerFactoryBean.getConfigurationTransactionManager();
        if (tm == null) {
            tm = HibernateSessionFactoryBean.getConfigurationTransactionManager();
        }

        if (tm == null) {
            throw new IllegalStateException(
                    "No JTA TransactionManager found - "
                            + "'hibernate.transaction.jta.platform' property must be set on the containing LocalSessionFactoryBean or LocalEntityManagerFactoryBean as appropriate");
        }

        this.transactionManager = tm;
    }

We've solved the integration part. So now we only need configure the EntityManager using our specialised subclass, injecting the transaction manager into it, and configuring our JtaPlatform as a Hibernate property. The configuration is completely portable - we just need to change the specification of our transaction manager bean.

Unfriendly Containers

Some containers (one in particular) stand out as being unfriendly to this strategy because although they implement JtaTransactionManager as part of the Spring provided class, their getTransactionManager()  method doesn't return anything meaningful. IBM's WebSphere is the standout example as they fulfill the JTA contracts in Spring using the proprietary Unit Of Work API. To get this environment working with our approach we need to extend the Spring provided class to return a valid transaction manager instance. What we actually will do is return an adapter that fulfills (enough) of the JTA API by delegating to the WebSphere Unit of Work API. A pure Hibernate solution for this is documented at itdevworld. Its straightforward to adapt this approach by subclassing WebSphereUowTransactionManager. Here's the code:

public class SpringWebSphereUowTransactionManager extends WebSphereUowTransactionManager {

    private static final long serialVersionUID = 4838070722625854290L;

    private static final String UOW_SYNCHRONIZATION_REGISTRY_JNDINAME = "java:comp/websphere/UOWSynchronizationRegistry";
    private static final String USER_TRANASCTION_JNDINAME = "java:comp/UserTransaction";

    private static final Field UOW_FIELD;

    static {
        try {
            UOW_FIELD = WebSphereUowTransactionManager.class.getDeclaredField("uowManager");
            UOW_FIELD.setAccessible(true);
        } catch (SecurityException e) {
            throw new IllegalStateException(
                    "Not permitted to access WebSphereUowTransactionManager: " + e.getMessage(), e);
        } catch (NoSuchFieldException e) {
            throw new IllegalStateException("Could not find WebSphereUowTransactionManager: " + e.getMessage(), e);
        }
    }

    /**
     * Creates a new instance
     */
    public SpringWebSphereUowTransactionManager() {
        super();
    }

    @Override
    public void afterPropertiesSet() throws TransactionSystemException {
        super.afterPropertiesSet();
        setTransactionManager(new TransactionManagerAdapter(getJndiTemplate(), retrieveUowManager()));
        setUserTransactionName(USER_TRANASCTION_JNDINAME);
    }

    private Object retrieveUowManager() {
        try {
            Object uowManager = UOW_FIELD.get(this);
            return uowManager;
        } catch (SecurityException e) {
            throw new IllegalStateException(
                    "Not permitted to access WebSphereUowTransactionManager: " + e.getMessage(), e);
        } catch (IllegalArgumentException e) {
            throw new IllegalStateException("Unexpected argument accessing WebSphereUowTransactionManager: "
                    + e.getMessage(), e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception accessing WebSphereUowTransactionManager: "
                    + e.getMessage(), e);
        }
    }

    /**
     * An adapter that fulfils the JTA {@link TransactionManager} by delegating to the WebSphereUOWTransactionManager
     */
    public static class TransactionManagerAdapter implements TransactionManager {

        private final JndiTemplate jndiTemplate;

        private final Object uowManager;
        private final Class<?> uowManagerClass;

        private final Object uowSynchronizationRegistry;
        private final Class<?> uowSynchronizationRegistryClass;

        private final Method registerSynchronizationMethod;
        private final Method setRollbackOnlyMethod;

        private final Class<?> extendedJTATransactionClass;
        private final Method getLocalIdMethod;

        /**
         * Create a new instance
         * @param jndiTemplate An instance of Spring's JndiTemplate to use to look up resources
         * @param uowManager UOWManager to use
         */
        private TransactionManagerAdapter(JndiTemplate jndiTemplate, Object uowManager) {

            try {
                this.uowManagerClass = Class.forName("com.ibm.ws.uow.UOWManager");

                this.uowSynchronizationRegistry = jndiTemplate.lookup(UOW_SYNCHRONIZATION_REGISTRY_JNDINAME);
                this.uowSynchronizationRegistryClass = Class
                        .forName("com.ibm.websphere.uow.UOWSynchronizationRegistry");

                this.registerSynchronizationMethod = uowSynchronizationRegistryClass.getMethod(
                        "registerInterposedSynchronization", new Class[] { Synchronization.class });
                this.setRollbackOnlyMethod = uowManagerClass.getMethod("setRollbackOnly", new Class[] {});

                this.extendedJTATransactionClass = Class
                        .forName("com.ibm.websphere.jtaextensions.ExtendedJTATransaction");
                this.getLocalIdMethod = extendedJTATransactionClass.getMethod("getLocalId", (Class[]) null);

            } catch (ClassNotFoundException e) {
                throw new IllegalStateException("Could not find required WebSphere class: " + e.getMessage(), e);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("Could not find required method: " + e.getMessage(), e);
            } catch (NamingException e) {
                throw new IllegalStateException("Problem accessing JNDI: " + e.getMessage(), e);
            }

            this.jndiTemplate = jndiTemplate;
            this.uowManager = uowManager;
        }

        @Override
        public void begin() {
            throw new UnsupportedOperationException("begin() is not supported");
        }

        @Override
        public void commit() {
            throw new UnsupportedOperationException("commit() is not supported");
        }

        @Override
        public int getStatus() {
            throw new UnsupportedOperationException("getStatus() is not supported");
        }

        @Override
        public void resume(Transaction txn) {
            throw new UnsupportedOperationException("resume() is not supported");
        }

        @Override
        public void rollback() {
            throw new UnsupportedOperationException("rollback() is not supported");
        }

        @Override
        public void setTransactionTimeout(int i) {
            throw new UnsupportedOperationException("setTransactionTimeout() is not supported");
        }

        @Override
        public Transaction suspend() {
            throw new UnsupportedOperationException("suspend() is not supported");
        }

        @Override
        public void setRollbackOnly() throws IllegalStateException {
            try {
                setRollbackOnlyMethod.invoke(uowManager, new Object[] {});
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Could not access setRollbackOnly() on UOWManager: " + e.getMessage(),
                        e);
            } catch (InvocationTargetException e) {
                throw new IllegalStateException("Could not invoke setRollbackOnly() on UOWManager: " + e.getMessage(),
                        e);
            }
        }

        @Override
        public Transaction getTransaction() {
            return new TransactionAdapter(jndiTemplate);
        }

        /**
         * An adapter that fulfils the JTA transaction interface.
         */
        public class TransactionAdapter implements Transaction {

            private final Object extendedJTATransaction;

            /**
             * Creates a new instance
             * @param template The JndiTemplate
             */
            private TransactionAdapter(JndiTemplate template) {
                try {
                    extendedJTATransaction = template.lookup("java:comp/websphere/ExtendedJTATransaction");

                } catch (NamingException e) {
                    throw new IllegalStateException("Could not find ExtendedJTATransaction in JNDI: " + e.getMessage(),
                            e);
                }
            }

            @Override
            public void registerSynchronization(final Synchronization synchronization) {

                try {
                    registerSynchronizationMethod.invoke(uowSynchronizationRegistry, new Object[] { synchronization });
                } catch (IllegalArgumentException e) {
                    throw new IllegalStateException("Unexpected argument accessing UOWSynchronizationRegistry: "
                            + e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unexpected exception accessing UOWSynchronizationRegistry: "
                            + e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    throw new IllegalStateException(
                            "Could not invoke registerSynchronization() on UOWSynchronizationRegistry: "
                                    + e.getMessage(), e);
                }
            }

            @Override
            public void commit() {
                throw new UnsupportedOperationException("commit() is not supported");
            }

            @Override
            public boolean delistResource(XAResource resource, int i) {
                throw new UnsupportedOperationException("delistResource() is not supported");
            }

            @Override
            public boolean enlistResource(XAResource resource) {
                throw new UnsupportedOperationException("enlistResource() is not supported");
            }

            @Override
            public int getStatus() {
                if (0 == getLocalId()) {
                    return Status.STATUS_NO_TRANSACTION;
                } else {
                    return Status.STATUS_ACTIVE;
                }
            }

            @Override
            public void rollback() throws IllegalStateException, SystemException {
                throw new UnsupportedOperationException("rollback() is not supported");
            }

            @Override
            public void setRollbackOnly() {
                try {
                    setRollbackOnlyMethod.invoke(uowManager, new Object[] {});
                } catch (IllegalArgumentException e) {
                    throw new IllegalStateException("Unexpected argument accessing UOWManager: " + e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unexpected exception accessing UOWManager: " + e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    throw new IllegalStateException("Could not invoke setRollbackOnly() on UOWManager: "
                            + e.getMessage(), e);
                }
            }

            @Override
            public int hashCode() {
                return getLocalId();
            }

            @Override
            public boolean equals(Object other) {
                if (!(other instanceof TransactionAdapter))
                    return false;
                TransactionAdapter that = (TransactionAdapter) other;
                return getLocalId() == that.getLocalId();
            }

            private int getLocalId() {
                try {
                    return ((Integer) (getLocalIdMethod.invoke(extendedJTATransaction, (Object[]) null))).intValue();
                } catch (IllegalArgumentException e) {
                    throw new IllegalStateException("Unexpected argument accessing ExtendedJTATransaction: "
                            + e.getMessage(), e);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unexpected exception accessing ExtendedJTATransaction: "
                            + e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    throw new IllegalStateException("Could not invoke getLocalId() on ExtendedJTATransaction: "
                            + e.getMessage(), e);
                }
            }

        }
    }
}

Unit Testing

I've still not discussed how unit testing can be performed with JTA. In the past this used to be quite tricky, but now its straightforward using JBoss Narayana (formerly JBoss Transactions, formely Arjuna).

Narayana needs to be added as a test build dependency:

            <dependency>
                <groupId>org.jboss.narayana.jta</groupId>
                <artifactId>narayana-jta</artifactId>
                <version>5.0.1.Final</version>
                <scope>test</scope>
            </dependency>

 And the Spring Transaction manager that uses Narayana needs to be declared:

<bean id="jbossTransactionManager" class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple">
        <property name="transactionTimeout" value="300" />
    </bean>

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <ref bean="jbossTransactionManager" />
        </property>
        <property name="allowCustomIsolationLevels" value="true" />
    </bean>

The configuration is ready for Unit Testing.

I've had to solve this problem many times - I hope the solution is useful.

You'll find the full code in the usertype.spi module in the package org.jadira.usertype.spi.jta. Do let me know if you can suggest improvements or find problems with it.

Saturday
Apr192014

Classes for IO

Jadira 3.2.0.GA will introduce some new classes for IO as part of a jadira-lang module. See JDF-77.

These address adapting NIO and traditional Java IO streams, optimised Buffered Stream inplementations, and an extension of the SAX InputSource that supports a variety of Source providers including the Spring Resource abstraction.

IO2NIO

This package provides two classes. ByteBufferBackedOutputStream is a custom OutputStream that writes to a ByteBuffer. ByteBufferBackedInputStream exposes reading from a ByteBuffer via an InputStream.

Core

I have frequently had the need to create similar classes to this one, so its well overdue to include it into Jadira. The class is a subclass of SAXInputSource. Its key feature is the variety of types from which the InputSource can be constructed - constructors are provided for File, InputStream, InputStreamSource, Resource (from Spring Framework) and URL.

Buffered

This package provides classes intended to be be used as an alternative to BufferedInputStream and BufferedOutputStream. Unlike those JDK classes they do not provide synchronization of their methods.

The following classes are provided for InputStream capabilities:

AbstractBufferedInputStream provides base functionality. It recreates some functionality from BufferedInputStream, but is organised to facilitate extendability. Whilst it does not subclass BufferedInputStream it instead subclasses FilterInputStream (the superclass of BufferedInputStream), so can be used in many of the same places.

Three subclasses exist, these are backed by DirectByteBuffer, ByteBuffer and a byte array respectively.

For OutputStream, equivalent buffered classes are provided with similar properties:

Monday
Apr072014

Fixing Netflix Error N8156-6023 with Firefox

I've been scratching my head on this for a while. The error occurred with Firefox 28 and Silverlight 5. Reinstalls, clearing session, deleting C:\ProgramData\Microsoft\PlayReady\mspr.hds all did nothing.

The working solution was straightforward in the end:

  1. Run C:\Program Files\Microsoft Silverlight\5.1.30214.0\Silverlight.Configuration.exe, then click on 'Application Storage' and 'Delete All'. Ensure 'Enable Application Storage' is left ticked.
  2. Close Firefox, then right-click its icon, then right-click on 'Mozilla Firefox' and 'Run As Administrator'.
  3. Once launched, select 'Help' and 'Restart with Add-ons Disabled'.
  4. When Firefox launches, select 'Safe Mode' and wait for Firefox to launch.
  5. Browse to Netflix and watch a film.
  6. Close Firefox and restart it.

I hope this helps anyone else getting the same issue.

 

Tuesday
Mar112014

Announcing Jadira 3.1.0.GA

I’ve just released Jadira 3.1.0.GA. Its currently being promoted to Maven Central so may be a few hours before it shows up there.

This release follows nearly a year and half since our last stable release (3.0.0.GA) and eleven candidate releases. It is definitely time for the GA release, with many users tracking the CR releases which now significantly exceed 3.0.0 in usage.

Everyone using 2.0.x and 3.0.x should now be thinking of upgrading.

In 3.1.0 there are significant new features, evolution to existing capabilities and a significant strengthening to the codebase.

Key features in this release include:

Usertype

  • Support for:
    • JSR310 (Java 8)
    • ThreeTen Backport
    • Joda Time
    • Legacy JDK Temporal types
    • Joda Money
    • JDK Enums
    • Libphonenumber (uses Jadira’s cdt – common data types module)
    • ISO Country Codes (uses Jadira’s cdt – common data types module)
  • New Timezone managing algorithm. Especially MySQL users need to pay attention as they now need to set the JDBC connection property 'useLegacyDatetimeCode=false'
  • Global configuration options reduce domain verbosity. These exist for type auto-registration, java and database timezones, default currency codes and sequence generation seeds.
  • Typesafe, plumbing free and multiple-tier friendly JPA repositories.

Documentation has also been improved with (almost) comprehensive Javadoc and an enhanced (if still terse) user guide for the Usertypes modules at http://jadira.sourceforge.net/usertype-userguide.html.

Cloning

  • The first release for a high performance object cloning library with ASM, Reflection, InvokeDynamic and sun.misc.Unsafe based access strategies. Cloning introduces variants on the commons-lang HashCodeBuilder and EqualsBuilder that take advantage of the object access strategies. Cloning can be integrated with Orika to provide a cloning converter as part of a larger transformation.

Bindings

  • Extensible framework for registering and invoking conversions of objects from one class to another

Scanner

  • A multi-threaded library for classpath inspection in the spirit of Scannotation.

I’ll be continuing to add to the documentation for the various moules with successive releases.

Jadira aims to deliver the building blocks for domain driven applications that perform well with minimal code and a rich type safe model. As Jadira moves towards the next release I’ll be working on extending the features with more tooling that supports building rich domains that integrate well with the event driven style.

 As usual, please give feedback via our issue tracker (http://jadira.atlassian.net/) and GitHub (https://github.com/JadiraOrg/jadira/)  or through the mailing list.

 A big vote of thanks to all the users who have provided bug reports, and suggested fixes and new features during the preparation of the release.

Saturday
Jun292013

Eclipse Kepler

Eclipse Kepler is the simultaneous release of Eclipse 4.3 and a large collection of related Eclipse projects. This release is the significant improvement over Eclipse Juno release, and with some small tweaks even some of the (still unsolved) user interface issues can be fully solved and forgotten.

This post updates my previous quick configuration howtos covering Ganymede, Galileo, Helios, Indigo and Juno by documenting the steps to get stock Eclipse up and running with essential Eclipse plugins. The recipe is for Windows - extrapolate as required.

1. Download Eclipse IDE for Java EE (eclipse-jee-kepler-SR2-win32.zip for 32-bit Windows, eclipse-jee-kepler-SR2-win32-x86_64.zip for 64-bit Windows). These can be found via http://www.eclipse.org/downloads/

2. Make a folder for Eclipse somewhere called 'Eclipse', and unzip the Eclipse SDK zip file to the parent folder. I typically create c:\Java\Eclipse and unzip to c:\Java

3. Create a shortcut to Eclipse, for example:

C:\Java\Eclipse\eclipse.exe

4. Configure eclipse.ini, for example, with the following for 32-bit Windows:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20140116-2212
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
-clean
-vm
C:/Java/JSE7/jre/bin/server/jvm.dll
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.7
-Dhelp.lucene.tokenizer=standard
-server
-Dcom.sun.management.jmxremote
-Declipse.p2.unsignedPolicy=allow
-Xms768m
-Xmx768m
-XX:MaxPermSize=256M
-XX:+UseG1GC
-XX:+TieredCompilation
-XX:+UseCompressedStrings
-XX:+UseCompressedOops

Use the following as an example for 64-bit Windows:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.200.v20140116-2212
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
--launcher.XXMaxPermSize
256M
-showsplash
org.eclipse.platform
-clean
-vm
C:/Java/JSE7/jre/bin/server/jvm.dll
--launcher.appendVmargs
-vmargs
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.7
-Dhelp.lucene.tokenizer=standard
-server
-Dcom.sun.management.jmxremote
-Declipse.p2.unsignedPolicy=allow
-Xms1536m
-Xmx1536m
-XX:MaxPermSize=256M
-XX:+UseG1GC
-XX:+TieredCompilation
-XX:+UseCompressedStrings
-XX:+UseCompressedOops

Modify the ‘vm’ argument so that it points to your appropriate Java runtime with Eclipse - this should be at least version 7.0 and should be 32-bit or 64-bit as appropriate. Best practice is to point to a JDK rather than a JRE location.

5. Next, search for new features using the Kepler Updates (with only "Show the latest version", "Group Items by Category" and "Contact all update sites during install to find required software" selected). Pick the appropriate platform features - you can safely select everything. Pick the appropriate platform features - you can safely select everything.

Typical selection could be:

  • Collaboration (Commandline interface for Java implementation of Git, Eclipse Git Team Provider, Eclipse Github Integration with task focused interface, Java Implementation of Git, Java Implementation of Git - optional Java 7 libraries, m2e - Maven Integration for Eclipse, m2e - slf4j over logback logging (Optional), Mylyn Builds Connector: Hudson/Jenkins, Mylyn Context Connector: Eclipse IDE, Mylyn Context Connector: Ecore Tools, Mylyn Context Connector: EMF, Mylyn Context Connector: GMF, Mylyn Context Connector: Java Development, Mylyn Context Connector: Team Support, Mylyn Intent, Mylyn Intent - Workspace support, Mylyn Intent Connector: Java, Mylyn Intent Generator: Intent Documentation, Mylyn Task List, Mylyn Task-Focused Interface, Mylyn Tasks Connector: Bugzilla, , Mylyn Tasks Connector: Trac, Mylyn Versions Connector: Git, Mylyn WikiText, Mylyn WikiText: Additional Generators, Task focued interface for Eclipse Git Team Provider)
  • Programming Languages (Code Recommenders Developer Tools)
  • Web XML Java EE and OSGi Development (Dali Java Persistence Tools - JPA Diagram Editor, Dali Java Persistence Tools - JPA Support)

6. After restarting, the following update sites can be used to add essential plugins:

AJDT http://download.eclipse.org/tools/ajdt/43/dev/update (Not AspectJ Development Tools Source or Equinox Weaving SDK)
AJDT AspectJ Configurer http://dist.springsource.org/release/AJDT/configurator/
SvnKit http://eclipse.svnkit.com/1.8.x
SubClipse http://subclipse.tigris.org/update_1.10.x
Log4E http://log4e.jayefem.de/update (note that the free version cannot be installed using the update site)
Eclipse FullScreen http://scharf.gr/eclipse/fullscreen/update/ (Not Experimental)
ByteCode Outline http://andrei.gmxhome.de/eclipse/ (only ByteCode Outline)
RegexUtil http://regex-util.sourceforge.net/update/
then restart

Also, from the Mylyn for Eclipse Kepler update site select all updates except for Mylyn Context Connector: C/C++ Development, Mylyn Reviews Connector: Gerrit, Mylyn Versions Connector: CVS, Mylyn Builds SDK, Mylyn Commons SDK, Mylyn Commons SOAP SDK, Mylyn Context SDK, Mylyn Docs EPUB SDK, Mylyn Docs SDK, Mylyn Reviews SDK, Mylyn Tasks SDK, Mylyn Tasks Tests SDK, Mylyn Versions SDK and Mylyn WikiText SDK).

7. After restarting again, install the following extensions from the Eclipse Marketplace: Maven Integration for Eclipse (Juno and newer), JavaCC Eclipse Plug-in,  EGit - Git Team Provider, GitHub Mylyn Connector, Mylyn WikiText, Spring Tool Suite (STS) for Eclipse Kepler, JBoss Tools (Kepler), Apt M2E Connector, Atlassian Connector for Eclipse, Java 8 support for Eclipse Kepler SR2, Java 8 Facet for Web Tools for Eclipse Kepler SR2, Eclipse Java 8 Support (for Kepler SR2) JDT, PDE 1.0.0, and Java 8 support for m2e for Eclipse Kepler SR2. If there are any conflicts at this stage, resolve them by keeping what you have already installed.

8. Go to "Window / Preferences / Maven / Discovery" and "Open Catalog". Select antlr, buildhelper, m2e connector for org.codehaus.mojo:jaxb2-maven-plugin, m2e-jdt-compiler, m2e-egit, m2e-subclipse (NB. Installation of m2e-subclipse does not appear to be working yet).

9. A couple of plugins are best installed by hand:

Download DBViewer from http://sourceforge.jp/projects/dbviewer/releases/ and copy the Jar to the Eclipse/dropins/plugins subdirectory
Download Tarlog Plugin 1.4.2 from http://code.google.com/p/tarlog-plugins/ (I used tarlog.eclipse.plugins_1.4.2.jar) and copy the Jar to the Eclipse/dropins/plugins subdirectory.

10. Some other Plugins from the Marketplace that you might want to install: QWickie, Apache Directory Studio, TestNG for Eclipse, Bndtools, Checkstyle, PMD, FindBugs Eclipse Plugin

11. If you cannot open Window / Preferences / General / Appearances without an error dialog appearing add to eclipse.ini just before the '-clean' line:

-cssTheme
org.eclipse.e4.ui.css.theme.e4_default

12. If the layout of your toolbar buttons looks poor and you cannot drag and drop them, install Jeeeyul's 'Eclipse 4 Chrome Theme' from the Eclipse Marketplace. Restart then go to Window / Preferences / General / Appearance' and select 'Jeeeyul's themes - Chrome Theme'.  Restart again and the problem should be solved.

13. I prefer the standard Java branding even when I have installed from the JavaEE IDE distribution. To get this packaging, I change -product in eclipse.ini to:

-product
org.eclipse.epp.package.standard.product

Then, from the standard distribution of Eclipse, I unzip the folder eclipse/plugins/org.eclipse.epp.package.standard_2.0.2.20140224-0000 to the equivalent directory in my Eclipse installation. The next Eclipse restart will use the standard branding.