Enterprise JavaBeans

Эта статья находится на начальном уровне проработки, в одной из её версий выборочно используется текст из источника, распространяемого под свободной лицензией
Материал из энциклопедии Руниверсалис
(перенаправлено с «EJB»)

Enterprise JavaBeans (также часто употребляется в виде аббревиатуры EJB) — спецификация технологии написания и поддержки серверных компонентов, содержащих бизнес-логику. Является частью Java EE.

Эта технология обычно применяется, когда бизнес-логика требует как минимум один из следующих сервисов, а часто все из них:

  • поддержка сохранности данных (persistence); данные должны быть в сохранности даже после остановки программы, чаще всего достигается с помощью использования базы данных
  • поддержка распределённых транзакций
  • поддержка параллельного изменения данных и многопоточность
  • поддержка событий
  • поддержка именования и каталогов (JNDI)
  • безопасность и ограничение доступа к данным
  • поддержка автоматизированной установки на сервер приложений
  • удалённый доступ

Каждый EJB-компонент является набором Java-классов со строго регламентированными правилами именования методов (верно для EJB 2.0, в EJB 3.0 за счет использования аннотаций выбор имён свободный). Бывают трёх основных типов:

  • объектные (Entity Bean) — перенесены в спецификацию Java Persistence API
  • сессионные (Session Beans), которые бывают
    • stateless (без состояния)
    • stateful (с поддержкой текущего состояния сессии)
    • singleton (один объект на все приложение; начиная с версии 3.1)
  • управляемые сообщениями (Message Driven Beans) — их логика является реакцией на события в системе

Пример Entity Bean

package org.test.entity;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
import javax.validation.constraints.Size;
import org.test.entity.listener.GalleryListener;

@Entity
@EntityListeners({GalleryListener.class})
@Table(name = "gallery",
    uniqueConstraints = {
        @UniqueConstraint(columnNames = {"id"})
    }
)
@NamedQueries({
    @NamedQuery(name = Gallery.QUERY_FIND_ALL, query = "SELECT g FROM Gallery g ORDER BY g.name ASC"),
    @NamedQuery(name = Gallery.QUERY_FIND_BY_NAME, query = "SELECT g FROM Gallery g WHERE g.name = :name")
})
public class Gallery implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    public static final String QUERY_FIND_ALL = "Gallery.findAll";
    public static final String QUERY_FIND_BY_NAME = "Gallery.findByName";
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;
    
    @Size(max = 100)
    @Column(name = "name", length = 100)
    private String name;
    
    @Column(name = "created_at")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;

    public Gallery() {
    }

    public Gallery(String name) {
        this.name = name;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Gallery other = (Gallery) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 47 * hash + (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }
    
}

Пример Entity Bean Listener

package org.test.entity.listener;

import java.util.Date;
import javax.persistence.PrePersist;
import org.test.entity.Gallery;

public class GalleryListener {
    
    @PrePersist
    public void prePersist(Gallery gallery) {
        gallery.setCreatedAt(new Date());
    }
    
}

Пример Session Bean - Stateless EAO (Entity Access Object)

package org.test.eao;

import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.test.entity.Gallery;

@Stateless
@LocalBean
public class GalleryEAO extends AbstractEAO<Gallery> {
    
    @PersistenceContext(unitName = "PersistenceUnit")
    private EntityManager entityManager;

    public GalleryEAO() {
        super(Gallery.class);
    }
    
    @Override
    protected EntityManager getEntityManager() {
        return entityManager;
    }
    
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List<Gallery> findAll() {
        return namedQuery(Gallery.QUERY_FIND_ALL).getResultList();
    }
    
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public Gallery findByName(String name) {
        return namedQuery(Gallery.QUERY_FIND_BY_NAME)
                .setParameter("name", name)
                .getSingleResult();
    }   
}

Пример Abstract EAO (Entity Access Object)

package org.test.eao;

import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

public abstract class AbstractEAO<T extends Serializable> {

    protected abstract EntityManager getEntityManager();
    
    private Class<T> entityClass;

    public Class<T> getEntityClass() {
        return entityClass;
    }
    
    public AbstractEAO(Class<T> entityClass) {
        this.entityClass = entityClass;
    }
    
    public void persist(T entity) {
        getEntityManager().persist(entity);
    }
    
    public void merge(T entity) {
        getEntityManager().merge(entity);
    }
    
    public void remove(T entity) {
        if (entity != null) {
            getEntityManager().remove(entity);
        }
    }
    
    public void remove(Object id) {
        T entity = (T) getEntityManager().find(entityClass, id);
        remove(entity);
    }
    
    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }
    
    public void refresh(T entity) {
        getEntityManager().refresh(entity);
    }
    
    public TypedQuery<T> namedQuery(String queryName) {
        return getEntityManager().createNamedQuery(queryName, entityClass);
    }
    
    public TypedQuery<T> query(String queryString) {
        return getEntityManager().createQuery(queryString, entityClass);
    }
    
    public long count() {
        CriteriaQuery criteriaQuery = getEntityManager().getCriteriaBuilder().createQuery();
        Root<T> root = criteriaQuery.from(entityClass);
        criteriaQuery.select(getEntityManager().getCriteriaBuilder().count(root));
        Query query = getEntityManager().createQuery(criteriaQuery);
        
        return ((Long) query.getSingleResult()).longValue();
    }
}

Пример Session Bean (Stateless) - Gallery Facade

package org.test.facade;

import java.util.List;
import javax.ejb.*;
import org.test.eao.GalleryEAO;
import org.test.entity.Gallery;
import org.test.exception.GalleryAlreadyExistsException;
import org.test.exception.GalleryNotFoundException;

@Stateless
@LocalBean
public class GalleryFacade {
    
    @Inject
    private GalleryEAO galleryEAO;
    
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public Gallery findById(Long id) throws GalleryNotFoundException {
        Gallery gallery = galleryEAO.find(id);
        if (gallery == null) throw new GalleryNotFoundException("Gallery not found");
        return gallery;
    }
    
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List<Gallery> findAll() {
        return galleryEAO.findAll();
    }
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void create(String name) throws GalleryAlreadyExistsException {
        if (galleryEAO.findByName(name) != null) throw new GalleryAlreadyExistsException("Gallery already exists", name);
        Gallery gallery = new Gallery(name);
        galleryEAO.persist(gallery);
    }
   
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void remove(Long id) throws GalleryNotFoundException {
        Gallery gallery = findById(id);
        galleryEAO.remove(gallery);
    }
}

Пример Application Exception - GalleryNotFoundException

package org.test.exception;

import javax.ejb.ApplicationException;

@ApplicationException(rollback=true)
public class GalleryNotFoundException extends Exception {

    public GalleryNotFoundException() {
    }

    public GalleryNotFoundException(String message) {
        super(message);
    }    
}

Пример Application Exception - GalleryAlreadyExistsException

package org.test.exception;

import javax.ejb.ApplicationException;

@ApplicationException(rollback=true)
public class GalleryAlreadyExistsException extends Exception {

    private String name;
    
    public GalleryAlreadyExistsException() {
    }

    public GalleryAlreadyExistsException(String message, String name) {
        super(message);
        this.name = name;
    }

    public String getName() {
        return name;
    }   
}

Литература

  • Панда Д. EJB 3 в действии. — ДМК Пресс, 2014. — 618 с. — ISBN 978-5-97060-135-8.

Ссылки