2014-08-29 2 views
0

Кулак это не тот объект, но это неправильная ссылка, поскольку я поставил диагноз проблемы.GWT RequestFactory вызывающий сеттер на неправильном объекте

У меня есть редактор, где я редактирую объект, который содержит другой редактор списка из большего количества компонентов.

У меня есть TagCollectionProxy, и он содержит список объектов TagProxy. Проблема возникает, когда я сохраняю TagCollectionProxy со связанными объектами List. Мой локатор объектов ищет объект в базе данных и устанавливает значение, но тогда у меня нет ссылки на этот объект. Это новое, и я не уверен, почему это происходит сейчас.

Это сообщение отладки, когда я вызываю сохранение объекта. Я поместил сообщение в класс Tag на setValue, и вы можете видеть, что я устанавливаю правильное значение для объекта домена. Идентификатор совпадает. Проблема возникает в следующем сообщении для моего сохранения (TagCollection) в моем классе dao. Я повторяю сущности и печатаю значение, но значение не изменилось для этого объекта.

2014-08-29T15:34:15.912-0500|INFO: Setting value Tag2asdfasdfasdfasdf for id 294 Reference [email protected] 
2014-08-29T15:34:15.944-0500|INFO: Tag name => asdfasdf Tag value => Tag2 id => 294 ref => [email protected] 
2014-08-29T15:34:15.944-0500|INFO: Id of tag is 294 

Заранее благодарим за любую помощь, я теряю волосы на минуту.

Это моя деятельность, которая сохраняет объект. Обратите внимание, что я сохраняю TagCollectionProxy, который содержит список тегов.

public class TagCollectionEditActivity extends AbstractActivity<TagCollectionEditView> implements 
     TagCollectionEditView.Presenter { 



    private Receiver<Long> saveReceiver = new Receiver<Long>() { 
     @Override 
     public void onSuccess(Long response) { 
      logger.info("saved tagCollection with id of " + response); 
      clientFactory.getPlaceController().goTo(new TagCollectionsPlace()); 
     } 

     public void onConstraintViolation(Set<ConstraintViolation<?>> violations) { 

      for (ConstraintViolation<?> violation : violations) { 
       logger.warning(violation.getMessage()); 
      } 
      getDisplay().getEditorDriver().setConstraintViolations(violations); 
     } 

     public void onFailure(ServerFailure failure) { 
      logger.log(Level.SEVERE, "Failed to save tag collection " + failure.getMessage()); 
      getDisplay().showError(failure); 
     } 
    }; 

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

    private IClientFactory clientFactory; 

    private TagCollectionDaoRequest editContext = null; 

    public TagCollectionEditActivity(IClientFactory clientFactory) { 
     super(new TagCollectionEditView(clientFactory.getResources(), clientFactory.getEventBus())); 
     this.clientFactory = clientFactory; 
    } 

    @Override 
    protected void bindToView() { 
     getDisplay().setPresenter(this); 
     final TagCollectionEditPlace place = (TagCollectionEditPlace) getPlace(); 
     Long tagCollectionId = place.getTagCollectionId(); 

     if (tagCollectionId == null) { 
      createTagCollection(); 
     } else { 
      findCollection(tagCollectionId); 
     } 
    } 

    private void findCollection(Long tagCollectionId) { 
     clientFactory.tagCollectionRequest().find(tagCollectionId).with(getEntityProperties()) 
       .fire(new Receiver<TagCollectionProxy>() { 

        @Override 
        public void onSuccess(TagCollectionProxy tagCollection) { 
         editContext = clientFactory.tagCollectionRequest(); 
         editContext.save(tagCollection).with(getDisplay().getEditorDriver().getPaths()).to(saveReceiver); 
         getDisplay().getEditorDriver().edit(tagCollection, editContext); 
         GWT.log("Context is " + editContext.hashCode()); 
        } 
       }); 
    } 

    private void createTagCollection() { 
     editContext = clientFactory.tagCollectionRequest(); 
     TagCollectionProxy tagCollection = editContext.create(TagCollectionProxy.class); 
     editContext.save(tagCollection).with(getDisplay().getEditorDriver().getPaths()).to(saveReceiver); 
     tagCollection.setTags(new ArrayList<TagProxy>()); 
     getDisplay().getEditorDriver().edit(tagCollection, editContext); 
    } 

    @Override 
    public void onSave() { 
     RequestContext context = getDisplay().getEditorDriver().flush(); 
     context.fire(); 
    } 

    public String[] getEntityProperties() { 
     return new String[] { "tags", "deviceFamily" }; 
    } 

    @Override 
    public void onCancel() { 
     clientFactory.getPlaceController().goTo(new TagCollectionsPlace()); 
    } 
} 

Вот мой тег коллекция прокси, где я определяю мой DomainEntityLocator

@ProxyFor(value = TagCollection.class, locator = DomainEntityLocator.class) 
public interface TagCollectionProxy extends DomainEntityProxy { 

    public List<TagProxy> getTags(); 

    public void setTags(List<TagProxy> tags); 

    public DeviceFamilyProxy getDeviceFamily(); 

    public void setDeviceFamily(DeviceFamilyProxy deviceFamily); 

} 

Вот мой локатор, который использует базу данных для поиска объектов с помощью JPA EntityManager.

public class DomainEntityLocator extends Locator<DomainEntity, Long> { 

    private static EntityManager em = null; 

    static { 
     Context initCtx; 
     try { 
      initCtx = new InitialContext(); 
      // perform JNDI lookup to obtain container-managed entity manager 
      em = (javax.persistence.EntityManager) initCtx.lookup("java:comp/env/persistence/DomainEntityManager"); 

     } catch (NamingException e) { 
      throw new RuntimeException("Unable to get the domain entity manager"); 
     } 
    } 

    public DomainEntityLocator() { 
    } 

    @Override 
    public DomainEntity create(Class<? extends DomainEntity> clazz) { 
     try { 
      return clazz.newInstance(); 
     } catch (InstantiationException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public DomainEntity find(Class<? extends DomainEntity> clazz, Long id) { 
     return em.find(clazz, id); 
    } 

    @Override 
    public Class<DomainEntity> getDomainType() { 
     return DomainEntity.class; 
    } 

    @Override 
    public Long getId(DomainEntity domainObject) { 
     return domainObject.getId(); 
    } 

    @Override 
    public Class<Long> getIdType() { 
     return Long.class; 
    } 

    @Override 
    public Object getVersion(DomainEntity domainObject) { 
     return 0; 
    } 
} 

Update

После некоторого исследования, я понял, что JPA на стороне сервера был виноват в моей проблеме. Я пришел к выводу, что DomainEntityLocator извлекает объект, но не переносит его в транзакцию. Таким образом метод DomainEntityLocator # find() будет извлекать объект, и ServiceLayer будет изменять значение для объекта. Проблема заключается в том, что метод find не заключен в транзакцию, и поскольку управляющий объект, который я получаю, не управляется, диспетчер сущности не очищает изменения. Поэтому я не вижу обновлений значения.

по теме Вопрос # 2

Есть общий шаблон для добавления управления транзакциями в Entity локатор, так что он будет сохраняться объектом после того, как запрос на завод вызывает сеттер. Я использовал это с помощью простого фильтра сервлетов, но для проекта, над которым я работаю, требуется java ee для поддержания такой функциональности. Я не могу сделать DomainEntityLocator фасоном без статусов из-за того, как ServiceLayer будет искать его. Было бы лучше расширить RequestFactoryServlet и обернуть doPost в tranasction? Это кажется самой логичной идеей. Какие-либо предложения?

Еще раз спасибо Томас

ответ

2

На стороне сервера, RequestFactory будет загружать каждый объект по его ID, с помощью локатора, поэтому TagCollection будет загружен (с его списком Tag) и каждый Tag будет загружен слишком использование DomainEntityLocator (предполагая, что они объявлены в их @ProxyFor).
Установщики будут вызываться на объектах, возвращаемых локатором, а не в списке TagCollectiongetTags.

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

С помощью JPA это означает использование шаблона «open session in view» (так называемый «сеанс на запрос»). В сеансе JPA используется кеш, поэтому совместное использование одного и того же сеанса по всему HTTP-запросу гарантирует, что те же экземпляры Tag используются при загрузке с TagCollection или непосредственно по их идентификатору.

+0

Томас, благодарю вас за помощь. Я пришел к тому же выводу, что и после небольшой отладки. Моя первоначальная путаница, связанная с Chrome, не печатает всего сообщения сообщения в панели предварительного просмотра (отладочные инструменты). Мне нужно было копаться в панели заголовка, чтобы увидеть все исходящее сообщение. Я обновил вопрос с незначительным обновлением. Если вы знаете хорошее решение для упаковки Locator в транзакции, если это даже хорошая идея, пожалуйста, дайте мне знать. –

+0

Обертка всего запроса/ответа в транзакции вызывает проблемы: семантика RF изменится, если вы это сделаете. Вам нужен шаблон «open session in view» (один «EntityManager» для каждого запроса/ответа), а затем охватите ваши транзакции к вашим методам обслуживания. –

0

Вот что я сделал для решения проблемы с EJB и RequestFactory.

После выяснения того, что метод RequestFactory не был обернут транзакцией для менеджера сущности, у меня было два выбора, которые приходили на ум. Один из них заключался в том, что я мог бы добавить UserTransaction в поиск и создание методов локатора Entity, но я решил обернуть весь запрос в транзакцию, и это хорошо работает для моего случая, так как мои методы фабрики запросов всегда должны быть в транзакции.

Я расширил requestfactory servlet и добавил UserTransaction для doPost.

@WebServlet("/rf/secure/dao") 
public class DmsRequestFactoryServlet extends RequestFactoryServlet { 

    private static final long serialVersionUID = -521670028586842819L; 

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

    @Resource 
    private UserTransaction tx; 


    public static class SimpleExceptionHandler implements ExceptionHandler { 

     @Override 
     public ServerFailure createServerFailure(Throwable throwable) { 
      logger.log(Level.SEVERE, "Unable to complete request", throwable); 

      return new ServerFailure("Server Error: " + (throwable == null ? null : throwable.getMessage()), throwable 
        .getClass().getName(), ExceptionUtils.getStackTrace(throwable), true); 
     } 
    } 

    @Override 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, 
      ServletException { 
     try { 
      tx.begin(); 
      super.doPost(request, response); 
      tx.commit(); 
     } catch (Exception e) { 
      logger.log(Level.SEVERE, "Failed request ", e); 
     } 
    } 

    public DmsRequestFactoryServlet() { 
     super(new SimpleExceptionHandler()); 
    } 
} 
Смежные вопросы