On 17/01/2014, at 1:42 am, Steve Ebersole <steve(a)hibernate.org> wrote:
On 01/16/2014 02:42 AM, Karl von Randow wrote:
> Hi all,
>
> I had a conversation with Steve today on IRC about refactoring the
org.hibernate.service package to make it standalone. The service registry implementation
is mostly separable from Hibernate core already, and it could be useful in other
applications perhaps where hibernate-core isn’t a dependency. I found myself in that exact
situation, which is why I’m here.
>
> I have done a test extraction of the service registry classes, excluding the
BootServiceRegistry, ClassLoaderService and StrategySelector families. This was quite
straight forward, worked well and worked with Hibernate core.
>
> Steve suggested that the boot service registry and associated class loading
functionality would be useful standalone as well. To see what that is like, I have now
done a test extraction including the BootServiceRegistry, ClassLoaderService and
StrategySelector families. It has worked quite well, but was definitely major.
What do you mean it "was ... major"? Difficult? I would think that those
would all peel-away pretty easily; that it would be "quite straight forward" as
you said.
The first part, without Boot + Class + StrategySelector is easy. The only interesting
dependencies are HibernateException, CoreMessageLogging and JmxService. I resolved all of
those pretty easily, and migrated JmxService into the org.hibernate.service.spi package,
next to its marker class Manageable.
I moved two log methods from CoreMessageLogging to the new ServiceRegistryMessageLogging.
The generated source is working nicely in Gradle, I presume there will be an i18n
implication for this.
The majorness (or is it major-ity) of the second part is related to the question below -
there were quite a few places where there was ORM specific functionality woven in. So from
that point of view, the standaloning may also be considered beautiful from a code
structure pov.
…
> The most interesting parts of migrating BootServiceRegistry et al over to the SSR is
the Hibernate ORM dependencies in BootServiceRegistry - specifically Integrators. There
were also Hibernate ORM specific features in StrategySelectorBuilder and
ClassLoaderServiceImpl (specifically ClassLoaderHelper). I have created subclasses in
hibernate-core of the implementations I moved to the SSR module, with the same class name
as the original. These subclasses provide the Hibernate specific functionality.
Ah, I had forgotten about the direct Integrator reference on BootServiceRegistry.
I'd have to think through that.
What "ORM specific features" are in StrategySelectorBuilder and
ClassLoaderServiceImpl?
I managed to separate Integrator pretty nicely I think. Hibernate core has its own
BootServiceRegistry implementation that supports Integrators by subclassing the new
AbstractBootServiceRegistry in SSR. I added the necessary hooks - one or two.
StrategySelectorBuilder loads dialects, JTA platforms, transaction factories and
multi-table bulk id strategies as part of its code. Again, this was easily separated out.
I created an AbstractStrategySelectorBuilder in SSR and a subclass
StrategySelectorBuilder, in its original place in core, that overrides a new
addBaseline(StrategySelectorImpl) protected method and calls the addDialects etc methods
extracted from the original. Pretty clean.
The StrategyRegistrationProvider was a bit interesting. This is referenced by its full
class name as property files in the individual modules to load strategy registration
providers. As you’ll note from the commit log I only discovered this later in the
migration. So I’ve added the capability to AbstractStrategySelectorBuilder to specify the
StrategyRegistrationProvider sub-interface to use, modifying the original
StrategyRegistrationProvider in core to extend the new one in SSR. This works pretty well.
I’ve then created a DefaultStrategySelectorBuilder to live in SSR which uses the
StrategyRegistrationProvider base-interface and doesn’t have any baseline strategies.
ClassLoaderServiceImpl has a dependency on ClassLoaderHelper, which allows overriding of
the context class loader. From the comments, this is a temporary solution, but I obviously
wanted to maintain it. There was also a deprecated method fromConfigSettings(Map
configValues) which is called from PersistenceXmlParser in JPA that I didn’t want to bring
to SSR as it contains core specific reference (AvailableSettings.HIBERNATE_CLASSLOADER
etc). I modified the original ClassLoaderServiceImpl to be a subclass of the impl in SSR
and to contain those specific pieces of functionality. I also modified the
BootstrapServiceRegistryBuilder so that it could choose the default ClassLoaderService
implementation, and core’s builder chooses core’s one.
I did all of the changes in little steps in the commit logs, so when it comes to the point
of following the process it should be pretty easy to see the thinking in each step!
> Another interesting standalone issue is the exception hierarchy. The exceptions no
longer extend from HibernateException. Perhaps it would be possible to have that class in
the SSR package and core to address this.
Not ideal, but not a deal-breaker either. Not convinced that *all* exceptions should be
runtime-variety anyway.
I only had to modify two tests, IIRC, that relied on those exceptions being
HibernateException subclasses. It doesn’t seem likely that much user code relies on those
exceptions as they feel much more internal to ORM. *fingers-crossed-emoji*