2012-10-03 10:55, Denis Gervalle skrev:
> On Wed, Oct 3, 2012 at 9:44 AM, Vincent Massol <[email protected]> wrote:
>
>> Hi Andreas,
>>
>> On Oct 3, 2012, at 9:22 AM, Andreas Jonsson <[email protected]> wrote:
>>
>>> +1 for extensible entity mappings.
>>>
>>> When registering a new mapping, i think that it should be possible to
>>> specify if it should apply to a particular wiki or to the whole farm.
>>> The collection of mappings for the whole farm should of course be
>>> enabled for new wiki instances.
>> Indeed that's a possibility and it'll almost work OOB with my proposal
>> since an extension can be installed only on a subwiki for ex. However it
>> would also require:
>> * ability to register core extensions for a given wiki
>> * have a session factory per wiki
>>
> If you use different session factories, there is no point to prefix
> mapping, and moreover this does not provide what Andreas expects, a single
> session across multiple databases.
>
>
>> And that's more complex. I'd like to finish my refactoring first and this
>> could be added later on if we agree about it since it won't impact much
>> what I'm working on.
>>
>> (see below)
>>
>>> While we are at it, we should try to find a better way to implement
>>> virtual wikis.  As I've already mentioned, I believe that this can be
>>> achieved by reregistering entity mappings per wiki, with prefixed entity
>>> names.  (This would really be the same as extensible entity mappings.)
>>> It seems that this should enable access to multiple wikis within the
>>> same Hibernate session, while being fully backwards compatible with the
>>> current implementation.
> I do not see how you expect to switch the accessed database during the
> session ?
>
>
>>  >
>>> But Denise wrote "[...] I doubt you will reach soon a state where
>>> hibernate support sessions across databases." and I'm not sure if he
>>> knows something about Hibernate limitations that would prevent this
>>> solution.
> Accessing multiple database in a single session is like seeing multiple
> database as a single one. I doubt hibernate will provide such
> implementation, since this is absolutely not the goal of that framework.
> The only potential implementation I could foresee to fulfill that needs, is
> a relaxed version of the upcoming multi-tenancy discriminator strategy,
> that would allow accessing the database without using the discriminator.
> But in that scenario, you would have only one database, so this not really
> what you expect.

I wrote a small test application to see how this would work.  The schema
and catalog parameters did not work as I expected.  But it does work on
both MySQL and PostgreSQL to instead use template with fully qualified
table name like this:

    <class name="${entityNamePrefix}:com.xpn.xwiki.doc.XWikiDocument"
           table="${databaseOrSchema}.xwikidoc">

I had to use two hacks to get it working:

1. I had to use a custom class loader just to strip the prefix from the
class name.  While the mapping from class to entity name can be
controlled by implementing the EntityNameResolver interface, there is
surprisingly no way to control the inverse mapping.  The entity name
(the name attribute of the class element) is passed directly to the
class loader.

2. The session factory interface does not contain the method
'registerEntityNameResolver', so I have to access the internal hibernate
class SessionFactoryImpl.

But I think that this is less kludgy than the current implementation.

The test application use these mappings:

  <class name="foo:se.kreablo.hibernatetest.TestEntity"
table="test_foo.testentity">
    <id name="id" column="id">
      <generator class="increment"/>
    </id>
    <property name="value" type="text" column="value"/>
  </class>

  <class name="bar:se.kreablo.hibernatetest.TestEntity"
table="test_bar.testentity">
    <id name="id" column="id">
      <generator class="increment"/>
    </id>
    <property name="value" type="text" column="value"/>
  </class>


public class HibernateTest
{

    private static class PrefixRemovingClassLoader extends ClassLoader
    {

        private String transformName(String name)
        {
            int i = name.indexOf(':');

            if (i > 0) {
                return name.substring(i + 1);
            }

            return name;
        }

        @Override
        public  Class<?> loadClass(String name) throws
ClassNotFoundException
        {
            return getParent().loadClass(transformName(name));
        }

    }

    private static class TestEntityNameResolver implements
EntityNameResolver
    {

        private String currentPrefix = "foo";

        @Override
        public String resolveEntityName(Object entity)
        {
            return currentPrefix + ":" + entity.getClass().getName();
        }

        public void setCurrentPrefix(String prefix)
        {
            currentPrefix = prefix;
        }

    }



    public static void main(String args[])
    {

        Thread.currentThread().setContextClassLoader(new
PrefixRemovingClassLoader());

        SessionFactory sessionFactory = new Configuration()
            .configure() // configures settings from hibernate.cfg.xml
            .buildSessionFactory();

        final TestEntityNameResolver entityNameResolver = new
TestEntityNameResolver();

        ((SessionFactoryImpl)
sessionFactory).registerEntityNameResolver(entityNameResolver);

        Session session = sessionFactory.openSession();

        session.beginTransaction();
        session.save( new TestEntity("First") );

        entityNameResolver.setCurrentPrefix("bar");
       
        session.save( new TestEntity("Second") );
        session.getTransaction().commit();
        session.close();
       
    }
}


Best Regards,

/Andreas

>>> The XML-schema for entity mappings allows for both a schema and catalog
>>> attributes to the class element.  If this is implemented in the expected
>>> way, it should work to use mapping templates such as:
>>>
>>>    <class name="${entityNamePrefix}:com.xpn.xwiki.doc.XWikiDocument"
>>>           table="xwikidoc" schema="${entitySchemaAttribute}">
>>>
>>> and for MySQL
>>>
>>>    <class name="${entityNamePrefix}:com.xpn.xwiki.doc.XWikiDocument"
>>>           table="xwikidoc" catalog="${entityCatalogAttribute}">
>>>
>>> And then you implement an EntityNamingStrategy for selecting the correct
>>> mappings for the current wiki.
>> BTW another solution could be to not any issue any schema change but to
>> have hibernate prefix all queries with the schema/catalog/user, e.g.
>> "select * from <dbname>.<table>". I couldn't find any built in support for
>> this but it could be possible to plug a new strategy - would need to ask
>> them.
>>
> I doubt this would really works in all kind of DB engines.
>
>
>> Thanks
>> -Vincent
>>
>>> Best Regards,
>>>
>>> /Andreas
>>>
>>>
>>> 2012-10-02 20:53, Vincent Massol skrev:
>>>> Hi devs,
>>>>
>>>> I'd like to propose the following to implement
>> http://jira.xwiki.org/browse/XWIKI-8271:
>>>> * Create a new xwiki-platform-store-hibernate module
>>>> * Add a Component role: HibernateConfiguration implements Comparable
>>>> * API: void HibernateConfiguration.configure(Configuration
>> aggregatedConfiguration), where the passed aggregatedConfiguration contains
>> the configuration filled by all the HibernateConfiguration.configure()
>> calls executed before
>>>> * Add a HibernateConfigurationManager.getConfiguration() component that
>> is in charge of loading the various HibernateConfiguration in the correct
>> order
>>>> * Have an AbstractHibernateConfiguration implements
>>  HibernateConfiguration with 1 API: getDatabaseType(Configuration
>> configuration). It gets the DB type from the connection URL string and
>> returns a DatabaseType object which represents the database type
>>>> * CoreHibernateMapping (hint = "xwiki") <==> xwiki.hbm.*.xml - highest
>> priority, defines the connection URL among other props
>>>> * ActivityStreamHibernateMapping (hint = "activitystream")
>>>> * FeedHibernateMapping (hint = "feeds")
>>>>
>>>> Note 1: If a HibernateConfiguration impl needs to load mappings that
>> depend on the DB they call AbstractHibernateConfiguration.
>> getDatabaseType() to get the DB.
>>>> Note 2: If the user wants to use a different HBM file, he/she just has
>> to put a file with the same name (e.g. xwiki.hbm.xml) in WEB-INF/classes
>>>> Note 3: This means we won't put any mapping anymore in the
>> hibernate.cfg.xml file since it's not needed anymore (although it would
>> continue to work if you put mappings there).
>>>> Usage:
>>>>
>>>> @Inject
>>>> HibernateConfigurationManager configurationManager;
>>>>
>>>> Configuration configuration = configurationManager.getConfiguration();
>>>> SessionFactory sessionFactory = configuration.buildSessionFactory();
>>>>
>>>> Then all that remains to implement
>> http://jira.xwiki.org/browse/XWIKI-8271 is to have a component singleton
>> that will be in charge of returning the SessionFactory and which can be
>> asked to rebuild a new SessionFactory (using a new Configuration).
>>>> We'll just need to decide how we trigger this. 2 options:
>>>> * By using an Event Listener listening on HibernateConfiguration
>> registrations and recreating automatically a new SessionFactory when it
>> happens. Cons: if an extension contributes several HibernateConfiguration
>> then Hibernate will be reinitialized several times
>>>> * By listening to an Event sent by the Extension Manager when an
>> extension has finished loading and somehow find out all the
>> HibernateConfiguration that have been added (several ways of doing this)
>> and recreating the SessionFactory
>>>> Note: The only issue I can foresee is if a Hibernate call is in
>> progress in one thread when an extension is installed and a new
>> SessionFactory is created at the same time. Either we don't care or we
>> could implement retry at the DB level, or we could introduce some semaphore
>> so that we start the reinit only when nobody has a lock on the
>> SessionFactory, or…
>>>> WDYT?
> Are you excluding the possibilities to use hibernate annotations, or do you
> expect to implements that in addition to an HibernateConfiguration
> implementation ?
>
>
>>>> Of course, the pros is those listed in
>> http://jira.xwiki.org/browse/XWIKI-8271:
>>>> * Ability for a platform module to contribute Hibernate mappings
>> (static)
>>>> * Ability for an extension installed at runtime to contribute Hibernate
>> mappings (dynamic)
>>>> Note that the reason I'm starting all this is because I'd like to
>> implement http://jira.xwiki.org/jira/browse/XWIKI-7953 cleanly in a
>> module separate from oldcore.
>>>> Thanks
>>>> -Vincent
>> _______________________________________________
>> devs mailing list
>> [email protected]
>> http://lists.xwiki.org/mailman/listinfo/devs
>>
>
> IMO, we should avoid pursuing with hacks over our Hibernate implementation.
> I am more in favor to remove our current, really underused custom solution,
> which is really expensive in maintenance compare the their real usage. In
> comparison, your proposal seem more clean, and a bit less dynamic. I do not
> think going too far and being too smart to be dynamic is really important.
> Providing extension a way to register their hibernate mapping, and at some
> point during wiki startup, building the hibernate session factory in a
> single step would be the cleanest and most efficient solution. When one or
> some new extensions are installed, and one or some of these extensions have
> registered an additional hibernate mapping, rebuilding the session factory
> once at the end of the installation would probably be the best.
>
> In regards to your proposal, if I well understand it, I am not sure the way
> you expect to chain the call to the configure() method is nice. It will
> implies that order could matter. While this would allow the ability to
> modify a configuration previously made, you will have no way to ensure such
> configuration has been made before. So there is no point to provide
> the aggregated configuration, unless you may ensure ordering. Maybe I have
> overlooked something ?
>

_______________________________________________
devs mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/devs

Reply via email to