Как заставить Контейнерно-управляемые транзакции (CMT) работать с EJB 3.1, Hibernate 3.6, JPA 2.0, JBoss и MySQL - PullRequest
1 голос
/ 22 марта 2011

Я пытался заставить CMT работать с JPA EntityManager и EJB, но обнаружил ошибку ниже.(стек транса урезан):

Caused by: java.lang.RuntimeException: **Could not resolve @EJB reference: [EJB Reference: beanInterface 'com.mydomain.beans.TestBean2', beanName 'testBean2', mappedName 'null', lookupName 'null',** owning unit 'AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}']
for environment entry: env/com.mydomain.action.SearchAction/testBean in unit AbstractVFSDeploymentContext@2008455195{vfs:///Users/willtardy/Documents/workspace/.metadata/.plugins/org.jboss.ide.eclipse.as.core/JBoss_6.0_Runtime_Server1300532851414/deploy/mydomainWeb.war}

Мои классы:

Сервлет, который обращается к Session Bean:

public class SearchActionExample extends Action {
    @EJB
    private static TestBeanServiceInterface testBean;

    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
        testBean.addSource("TEST SOURCE NAME", 88, 99);
        Service service = testBean.findService("HBA", "MEL");

        return mapping.findForward("success");
    }
}

Удаленный интерфейс:

@Remote
public interface TestBeanServiceInterface {
    // Source is my own custom entity
    void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients);

    // Service is my own Custom entity    
    Service findService(String departureAirportCode, String arrivalAirportCode);
}

Определение bean-компонента сеанса без сохранения состояния:

@Stateless
public class TestBeanService implements TestBeanServiceInterface {

    @PersistenceContext(unitName="mydomainJPA")
    private EntityManager em;

    public void addSource(String sourceName, int newthreadsleeptime, int maxactivehttpclients) {
        Source source = new Source();
        source.setName(sourceName);
        source.setNewThreadSleepTime(newthreadsleeptime);
        source.setMaxActiveHttpClients(maxactivehttpclients);
        em.persist(source);
    }
    public Service findService(String departureAirportCode, String arrivalAirportCode) {
        String queryString = "from Service where departureairportcode = '" + departureAirportCode + "' and arrivalairportcode = '" + arrivalAirportCode + "'";
        Service service = (Service)em.createQuery(queryString).getSingleResult();
        return service;
    }
}

file persistnce.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="mydomainJPA" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <class>com.mydomain.entities.Service</class>
<class>com.mydomain.entities.Source</class>
    <properties>
        <property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
        <property name="hibernate.archive.autodetection" value="class"/>
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
        <property name="hibernate.current_session_context_class" value="jta"/>   
    </properties>   
</persistence-unit>

Когда он говорит «не может разрешить ссылку», где еще я могу определитьбобы?EJB-JAR.XML не требуется с EJB3.Есть какой-то другой файл конфигурации, который мне не хватает?


ОБНОВЛЕНИЕ:

  • Я обновил сегменты кода выше, чтобывместо этого bean создается как тип интерфейса, как показано в ответе ниже.

  • Нужно ли определять или отображать EJB в файле web.xml?

  • Предполагая, что ссылка требуется в web.xml, я добавил ссылку на EJB в web.xml (см. Ниже), но теперь я получаю новую ошибку (см. Ниже)

Ответы [ 3 ]

1 голос
/ 22 марта 2011

Вам нужно ввести удаленный интерфейс, а не компонент

public class SearchActionExample extends Action {
    @EJB
    private static TestBean2Remote testBean;
0 голосов
/ 30 марта 2011

Я получил рабочий раствор:

@ Локальный интерфейс работает просто отлично (т.е. не обязательно должен быть удаленным)

Ссылки на bean-компоненты не требуются в файлах web.xml, ejb-jar.xml, application.xml или в любом файле конфигурации jboss.

Я запустил его, развернув в Eclipse в рамках «Проекта корпоративных приложений» (EAP). Этот проект содержит «Сборку развертывания», которая содержит файл .jar, содержащий классы сущностей JPA, и другой файл .jar, содержащий другие классы бизнес-логики. EAP имеет эти два проекта, плюс проект EJB и «Динамический веб-проект» (создает .war) для всего 4 проектов на своем пути сборки. Инструмент Jboss AS в Eclipse публикует / развертывает EAP на сервере Jboss. Содержимое application.xml в EAP, развертываемое в Jboss:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
    <display-name>myprojects</display-name>
    <module>
        <web>
            <web-uri>myproject.war</web-uri>
            <context-root>myproject</context-root>
        </web>
    </module>
    <module>
        <ejb>myprojectsEJB.jar</ejb>
    </module>
</application>

Класс локального интерфейса:

package com.myproject.beans;
import javax.ejb.Local;

import com.myproject.entities.Lion;

@Local
public interface SessionBeanLocal {
Lion addLion(String lionName);
}

Класс SessionBean:

package com.myproject.beans;

import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.myproject.Lion;

@Stateless
@Local(SessionBeanLocal.class)
public class SessionBean implements SessionBeanLocal {

@PersistenceContext(unitName="PersistenceUnitNameInPersistenceXML")
private EntityManager em;

public Lion addLion(String lionName) {
    Lion lion = new Lion(lionName);
    em.persist(lion);
}

НАИБОЛЕЕ ВАЖНОЕ изменение, которое заставило вещи работать: внутри класса, который содержит сессию, был переменным (например, внутри сервлета действия Struts, но мог быть любым сервлетом), для контейнера (JBoss AS) требовался метод установки для создания боб:

@EJB()
private SessionBeanLocal bean;

public void setBean(SessionBeanLocal bean) {
    System.out.println("setBean setter was called by container (e.g. Jboss)");
    this.bean = bean;
}

public exampleStrutsServletMethod(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
    PrintWriter out = response.getWriter();

    Lion lion = bean.addLion("Simba");  // this will persist the Lion within the persistence-context (and auto-generate an Id), and the container will manage when it's flushed to the database

    out.print("<html>LION ID = " + lion.getLionId() + "<html>");
}

file persistnce.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
<persistence-unit name="PersistenceUnitNameInPersistenceXML" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <properties>
    </properties>   
</persistence-unit>

mysql-dx.xml (в каталоге jboss-server-dir / server / default / deploy):

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
    <local-tx-datasource>
        <jndi-name>MySqlDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/myProjectDatabase</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>username</user-name>
        <password>mypassword</password>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
        <metadata>
            <type-mapping>mySQL</type-mapping>
        </metadata>
    </local-tx-datasource>
</datasources>

ПРИМЕЧАНИЕ. Классы не нужно определять в файле persistence.xml (через «»), если для «Persistance Class Management» установлено значение «Обнаруживать аннотированные классы автоматически» на панели свойств проекта «Java Persistence» для Eclipse. Проект JPA (т. Е. Проект, в котором содержатся классы сущностей JPA 2.0 и файл persistence.xml)

ПРИМЕЧАНИЕ. Это решение основано на: EJB3.1, Eclipse Helios SR2, Hibernate 3.6, JPA 2.0, JBoss 6, MySQL 5.5.10

ПРИМЕЧАНИЕ. Относительно «Управляемых контейнером транзакций» (CMT). Руководство по Hibernate ссылается на них и указывает, что вам нужно установить свойства persistence.xml, такие как "hibernate.transaction.factory_class", в значение: "org.hibernate.transaction.CMTTransactionFactory". Это не тот случай, если вы используете JPA EntityManager вместо собственного спящего режима. Мне не потребовалось никаких пользовательских свойств CMT в файле persistence.xml. Вот где Hibernate путается между двумя способами его реализации (то есть SessionFactory против EntityManager). Пожалуйста, не стесняйтесь комментировать эту часть моего решения, так как я все еще просто обдумываю его! Будет

0 голосов
/ 29 марта 2011
public class SearchActionExample extends Action {
    @EJB
    private static TestBeanServiceInterface testBean;

Не делать инъекции в статическое поле, инъекции являются элементами instance и происходят при создании объекта, тогда как статическое поле является членом class .Это, скорее всего, причина для исключения.

...