Устойчивость в среде OSGi с использованием Datanucleus JDO и чертежей

Я пытаюсь обеспечить постоянство в среде OSGi (Karaf работает с Felix) с максимально возможной модульностью. Я выбрал JDO из-за его дополнительных функций (в основном группы выборки) вместо JPA. Реализация является Datanucleus. Я использую Maven для создания всего проекта.

Поскольку у меня не было опыта работы с JDO или OSGi, было довольно сложно заставить работать любой из них. В настоящее время я могу сохранять JDO в среде Java SE (модульные тесты работают без проблем), и я знаю, как предоставлять услуги в среде OSGi с помощью контейнера чертежей. Но я не могу заставить эти две вещи работать вместе. У меня проблемы с загрузкой классов.

Мне не удалось создать даже простое приложение, которое могло бы сохранять JDO на Karaf (я пытался следовать этот учебник, но он использует Spring DM, и я не смог переписать его для использования схемы OSGi).

Меня больше всего смущает:

  • Какое значение следует установить для свойства datanucleus.primaryClassLoader?
  • Какой загрузчик классов передать в качестве аргумента методу JDOHelper.getPersistenceManagerFactory?
  • Какие пакеты явно импортировать с помощью maven-bundle-plugin? (похоже, могут потребоваться как минимум javax.jdo, org.datanucleus.api.jdo и org.osgi.framework)
  • Что нужно другим пакетам, кроме ссылки на PersistenceManagerFactory?

Кроме того:

  • Можно ли отделить информацию о сохранении от классов значений? Если я правильно понимаю, это было бы возможно только при использовании улучшения во время выполнения, что было бы очень сложно, если вообще выполнимо.
  • Можно ли определить взаимозависимые классы, поддерживающие сохраняемость, в нескольких пакетах? Например, определить пользователей в одном пакете и их адреса в другом?

Я был бы очень признателен за пример простого проекта с несколькими пакетами, который заботится о сохранении, используя только Datanucleus, JDO API и схему OSGi.

Спасибо


person binarek    schedule 25.09.2013    source источник


Ответы (1)


Я могу лишь дать несколько основных советов о том, как заставить JDO/datanucleus работать поверх Karaf.

Как указано в руководстве, вам необходимо расширить LocalPersistenceManagerFactoryBean, реализовав также интерфейс BundleContextAware.

Ключевым моментом здесь является загрузка классов: LocalPersistenceManagerFactoryBean ожидает, что все классы будут загружены одним единственным загрузчиком классов, чего нельзя сказать о среде выполнения OSGi.

Для того, чтобы заставить его работать, вам нужно:

  1. Явно импортируйте org.datanucleus.api.jdo в файл манифеста.
  2. Свойство datanucleus.primaryClassLoader может быть установлено для того же загрузчика классов, который вы передадите методу JDOHelper.getPersistenceManagerFactory. Загрузчик классов используется пакетом org.datanucleus.api.jdo (см. пример ниже).
  3. Вам нужно будет установить для свойства datanucleus.plugin.pluginRegistryClassName значение org.datanucleus.plugin.OSGiPluginRegistry.
  4. При остановке/удалении вашего пакета вам придется обновить пакет javax.jdo, чтобы избежать ошибок при повторном создании фабрики диспетчера постоянства (проверьте это вопрос по теме)

Пример пользовательского компонента LocalPersistenceManagerFactoryBean:

public class OSGiLocalPersistenceManagerFactoryBean
    extends LocalPersistenceManagerFactoryBean implements BundleContextAware {

    public static final String JDO_BUNDLE_NAME    = "org.datanucleus.api.jdo";
    public static final String JDO_PMF_CLASS_NAME = "org.datanucleus.api.jdo.JDOPersistenceManagerFactory";

    private BundleContext bundleContext;

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
        return JDOHelper.getPersistenceManagerFactory(name, getClassLoader());
    }

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
        ClassLoader classLoader = getClassLoader();

        props.put("datanucleus.primaryClassLoader", classLoader);

        if (FrameworkUtil.getBundle(this.getClass()) != null) { // running in OSGi
            props.put("datanucleus.plugin.pluginRegistryClassName", "org.datanucleus.plugin.OSGiPluginRegistry");
        }

        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props, classLoader);

        return pmf;
    }

    private ClassLoader getClassLoader() {
        ClassLoader classLoader = null;
        Bundle thisBundle = FrameworkUtil.getBundle(this.getClass());

        if (thisBundle != null) { // on OSGi runtime
            Bundle[] bundles = bundleContext.getBundles();

            for (Bundle bundle : bundles) {
                if (JDO_BUNDLE_NAME.equals(bundle.getSymbolicName())) {
                    try {
                        classLoader = bundle.loadClass(JDO_PMF_CLASS_NAME).getClassLoader();
                    } catch (ClassNotFoundException e) {
                        // do something fancy here ...
                    }
                    break;
                }
            }
        } else { // on Java runtime
            classLoader = this.getClass().getClassLoader();
        }
        return classLoader;
    }

    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
}
person el.atomo    schedule 24.10.2013
comment
Спасибо. Я это проверю. - person binarek; 06.11.2013
comment
Также обратите внимание, что все пакеты datanucleus должны быть запущены при запуске вашего пакета. Если не так выдает ошибку (NullPointerException) в OSGIPluginRegistry. - person Cristian Rinaldi; 12.01.2014