2015-07-08 4 views
3

Метод EJB (с использованием СМТ), который обновляет объект, поставляемый:Позволить презентационный слой (JSF) обрабатывать бизнес-исключения из службы слоя (EJB)

@Override 
@SuppressWarnings("unchecked") 
public boolean update(Entity entity) throws OptimisticLockException { 
    // Code to merge the entity. 
    return true; 
} 

Это забросить javax.persistence.OptimisticLockException, если обнаруживается одновременное обновление который должен обрабатываться именно вызывающим (управляемый компонент).

public void onRowEdit(RowEditEvent event) { 
    try { 
     service.update((Entity) event.getObject()) 
    } catch(OptimisticLockException e) { 
     // Add a user-friendly faces message. 
    } 
} 

Но делать это делает дополнительную зависимость от javax.persistence API на слой обязательной презентации, которая является дизайн запах приводит к жесткой муфтой.

В каком исключении оно должно быть обернуто так, чтобы проблема с плотным соединением могла быть опущена полностью? Или существует стандартный способ справиться с этим исключением, которое, в свою очередь, не приводит к принудительному выполнению зависимостей уровня сервиса на уровне презентации?

Кстати, я нашел неудобным, чтобы поймать это исключение в EJB (на самом уровне сервиса), а затем вернуть значение флага клиенту (JSF).

ответ

7

Создайте специальное исключение среды выполнения для определенного уровня сервиса, которое аннотируется @ApplicationException с помощью rollback=true.

@ApplicationException(rollback=true) 
public abstract class ServiceException extends RuntimeException {} 

Создать конкретные подклассы для общих бизнес-исключений, таких как нарушение ограничений, требуемого лица, и, конечно, оптимистической блокировки.

public class DuplicateEntityException extends ServiceException {} 
public class EntityNotFoundException extends ServiceException {} 
public class EntityAlreadyModifiedException extends ServiceException {} 

Некоторые из них могут быть выброшены непосредственно.

public void register(User user) { 
    if (findByEmail(user.getEmail()) != null) { 
     throw new DuplicateEntityException(); 
    } 

    // ... 
} 
public void addToOrder(OrderItem item, Long orderId) { 
    Order order = orderService.getById(orderId); 

    if (order == null) { 
     throw new EntityNotFoundException(); 
    } 

    // ... 
} 

Некоторые из них нуждаются в глобальной перехватчик.

@Interceptor 
public class ExceptionInterceptor implements Serializable { 

    @AroundInvoke 
    public Object handle(InvocationContext context) throws Exception { 
     try { 
      return context.proceed(); 
     } 
     catch (javax.persistence.EntityNotFoundException e) { // Can be thrown by Query#getSingleResult(). 
      throw new EntityNotFoundException(e); 
     } 
     catch (OptimisticLockException e) { 
      throw new EntityAlreadyModifiedException(e); 
     } 
    } 

} 

, который зарегистрирован как значение по умолчанию перехватчик (на всех EJBs), как показано ниже в ejb-jar.xml.

<interceptors> 
    <interceptor> 
     <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class> 
    </interceptor> 
</interceptors> 
<assembly-descriptor> 
    <interceptor-binding> 
     <ejb-name>*</ejb-name> 
     <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class> 
    </interceptor-binding> 
</assembly-descriptor> 

В общем намеке, в JSF вы можете также иметь глобальный обработчик исключений, который просто добавляет лицо сообщения. При запуске с this kickoff example, вы могли бы сделать что-то подобное в YourExceptionHandler#handle() методы:

if (exception instanceof EntityAlreadyModifiedException) { // Unwrap if necessary. 
    // Add FATAL faces message and return. 
} 
else { 
    // Continue as usual. 
} 
+0

Это немного не по теме, и, возможно, я пойду с отдельным вопросом, если я не могу получить решение. У меня есть тестовое приложение, содержащее только перехватчик ('javax.interceptor.Interceptor') с конфигурациями, упомянутыми здесь и одним EJB. Я всегда получаю исключение при развертывании - 'java.lang.IllegalStateException: привязка перехватчика содержит имя класса перехватчика = com.example.MyInterceptor, который не определен как перехватчик'. Что может быть вероятной причиной с первого взгляда? – Tiny

+0

См. Обновленный ответ для явной регистрации. Я думаю, GF4 не сделает этого, если нет '@ InterceptorBinding'. – BalusC

+0

Это работает сейчас. Благодарю.(Я не ожидал явной регистрации перехватчика таким образом). – Tiny