2012-05-09 3 views
0

У меня есть класс RMI, который принимает удаленные вызовы от клиентов.Как автоматизировать шаблон Hibernate в удаленных методах RMI

Этот класс использует Hibernate для загрузки объектов и выполнения некоторой бизнес-логики, в основном для чтения.

В настоящее время большинство органов удаленных методов выглядят так:

try { 
    HibernateUtil.currentSession().beginTransaction(); 

    //load entities, do some business logic... 

} catch (HibernateException e) { 
    logger.error("Hibernate problem...", e); 
    throw e; 
} catch (other exceptions...) { 
    logger.error("other problem happened...", e); 
    throw e; 
} finally { 
    HibernateUtil.currentSession().getTransaction().rollback(); //this because it's read-only, we make sure we don't commit anything 
    HibernateUtil.currentSession().close(); 
} 

Я хотел бы знать, если есть какой-то шаблон, который я мог (относительно легко) реализовать для того, чтобы автоматически иметь это «попытаться открыть session/catch hibernate exception/finally close hibernate resources "без необходимости кодировать его в каждом методе.

Что-то похожее на «открытый сеанс в представлении», который используется в webapps, но который может применяться к вызовам метода remotr RMI вместо HTTP-запросов.

В идеале я хотел бы иметь возможность по-прежнему напрямую обращаться к методам, а не использовать некоторые имена методов передачи рефлексии в виде строк.

ответ

0

Все, что я хотел, было «быстрым и чистым» решением, если это возможно, так что теперь нет новой структуры (позже я мог бы использовать Spring + Hibernate stack).

Таким образом, я закончил использование «быстрого и не столь грязного» решения с использованием варианта шаблона «Command», в котором вызовы hibernate инкапсулируются внутри анонимных внутренних классов, реализующих мой общий командный интерфейс, и command executer завершает вызов сеансом Hibernate и обработку исключений. Общий бит предназначен для того, чтобы иметь разные типы возвращаемых значений для метода execute.

Я не на 100% удовлетворен этим решением, поскольку он по-прежнему подразумевает какой-то шаблонный код, обернутый вокруг моей бизнес-логики (я особенно недоволен явным литьем, необходимым для возвращаемого значения), и это немного усложняет понимание и отлаживать.

Однако коэффициент усиления повторяющегося кода по-прежнему значителен (от 10 строк до 3-4 строк на метод), и, что более важно, логика обработки Hibernate сконцентрирована в одном классе, поэтому ее можно легко изменить там, если это необходимо, и он менее подвержен ошибкам.

Вот некоторые из кода:

Интерфейс командной:

public interface HibernateCommand<T> { 
    public T execute(Object... args) throws Exception; 
} 

Исполнитель:

public class HibernateCommandExecuter { 

    private static final Logger logger = Logger.getLogger(HibernateCommandExecuter.class); 

    public static Object executeCommand(HibernateCommand<?> command, boolean commit, Object... args) throws RemoteException{ 
     try { 
      HibernateUtil.currentSession().beginTransaction(); 

      return command.execute(args); 

     } catch (HibernateException e) { 
      logger.error("Hibernate problem : ", e); 
      throw new RemoteException(e.getMessage()); 
     }catch(Exception e){ 
      throw new RemoteException(e.getMessage(), e); 
     } 
     finally { 
      try{ 
       if(commit){ 
        HibernateUtil.currentSession().getTransaction().commit(); 
       }else{ 
        HibernateUtil.currentSession().getTransaction().rollback(); 
       } 
       HibernateUtil.currentSession().close(); 
      }catch(HibernateException e){ 
       logger.error("Error while trying to clean up Hibernate context :", e); 
      } 
     } 
    } 
} 

использование образца в дистанционно называемого метода (но она может быть использована на месте также):

@Override 
    public AbstractTicketingClientDTO doSomethingRemotely(final Client client) throws RemoteException { 
     return (MyDTO) HibernateCommandExecuter.executeCommand(new HibernateCommand<MyDTO>() { 
      public AbstractTicketingClientDTO execute(Object...args) throws Exception{ 
       MyDTO dto = someService.someBusinessmethod(client); 
       return dto; 
      } 
     },false); 
    } 

Обратите внимание, что аргумент клиента объявлен окончательным, поэтому он может быть указан во внутреннем классе. Если невозможно объявить окончательный, его можно передать как параметр методу executeCommand.

0

Я предлагаю вам использовать spring + hibernate Стек. Это экономит нам много повторяемого кода, который, я думаю, вы ищете. Пожалуйста, проверьте this link. Фактически это пример веб-приложения, но он также может использоваться для standalone application.

+0

Спасибо, я знаю, что Spring может помочь и, вероятно, в конце концов представит его проекту, но на данном этапе это не вариант. –

Смежные вопросы