details: https://code.openbravo.com/erp/devel/pi/rev/ea854655f9aa changeset: 28631:ea854655f9aa user: Asier Lostalé <asier.lostale <at> openbravo.com> date: Tue Feb 23 16:38:23 2016 +0100 summary: related to bug 32308: added test cases covering observers with ds update
details: https://code.openbravo.com/erp/devel/pi/rev/64dcdb9cf68b changeset: 28632:64dcdb9cf68b user: Asier Lostalé <asier.lostale <at> openbravo.com> date: Tue Feb 23 16:37:30 2016 +0100 summary: fixed bug 32308: error on update if an observer loaded current object in memory In case an entity observer loaded current object in memory (ie. observing orderLine) doing orderLine.getSalesOrder().getOrderLineList() there were two different instances in memory representing the same DB row. This caused problems when trying to evict it. Causing an exception to be thrown when updating from UI in this case. As solution eviction is no longer performed, object is forced to be fetched from DB by executing a Criteria. diffstat: modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/DatasourceEventObserver.java | 191 ++++++++++ modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/OrderLineTestObserver.java | 83 ++++ modules/org.openbravo.service.json/src/org/openbravo/service/json/DefaultJsonDataService.java | 18 +- src-test/src/org/openbravo/test/AllAntTaskTests.java | 4 +- src/org/openbravo/base/structure/BaseOBObject.java | 8 +- 5 files changed, 292 insertions(+), 12 deletions(-) diffs (truncated from 384 to 300 lines): diff -r 0f887315d105 -r 64dcdb9cf68b modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/DatasourceEventObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/DatasourceEventObserver.java Tue Feb 23 16:37:30 2016 +0100 @@ -0,0 +1,191 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.1 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo SLU + * All portions are Copyright (C) 2016 Openbravo SLU + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ + +package org.openbravo.client.application.test.event; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.util.HashMap; + +import javax.inject.Inject; + +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.hibernate.criterion.Restrictions; +import org.junit.AfterClass; +import org.junit.Test; +import org.openbravo.base.structure.BaseOBObject; +import org.openbravo.base.weld.test.WeldBaseTest; +import org.openbravo.client.application.Note; +import org.openbravo.dal.core.OBContext; +import org.openbravo.dal.service.OBCriteria; +import org.openbravo.dal.service.OBDal; +import org.openbravo.model.ad.datamodel.Table; +import org.openbravo.model.common.order.Order; +import org.openbravo.model.common.order.OrderLine; +import org.openbravo.service.datasource.DataSourceService; +import org.openbravo.service.datasource.DataSourceServiceProvider; +import org.openbravo.service.json.JsonConstants; + +/** + * Test cases covering updates through standard datasource that include a persistence observer. + * + * Observer is implemented in {@link OrderLineTestObserver}. + * + * @author alostale + * + */ +public class DatasourceEventObserver extends WeldBaseTest { + + @Inject + private DataSourceServiceProvider dataSourceServiceProvider; + + enum ObserverExecutionType { + OFF, UPDATE_DESCRIPTION, CREATE_NOTE, COUNT_LINES, UPDATE_PARENT + }; + + static ObserverExecutionType observerExecutionType = ObserverExecutionType.OFF; + + /** Updating order line without observer */ + @Test + public void standardUpdateRequestWithoutObserver() throws JSONException { + observerExecutionType = ObserverExecutionType.OFF; + + OrderLine ol = pickARandomOrderLine(); + + String randomDescription = Long.toString(System.currentTimeMillis()); + JSONObject updatedOrder = datasourceUpdate(ol, randomDescription); + + assertDescription(ol, updatedOrder, randomDescription); + } + + /** The observer updates line description to a fixed value */ + @Test + public void observerCanModifyPropertyValues() throws JSONException { + observerExecutionType = ObserverExecutionType.UPDATE_DESCRIPTION; + + OrderLine ol = pickARandomOrderLine(); + + String randomDescription = Long.toString(System.currentTimeMillis()); + JSONObject updatedOrder = datasourceUpdate(ol, randomDescription); + + assertDescription(ol, updatedOrder, OrderLineTestObserver.FORCED_DESCRIPTION); + } + + /** The observer creates a new note on order line */ + @Test + public void observerCanAddNewObjects() throws JSONException { + observerExecutionType = ObserverExecutionType.CREATE_NOTE; + + OrderLine ol = pickARandomOrderLine(); + int notesBeforeUpdate = countNotes(ol); + + String randomDescription = Long.toString(System.currentTimeMillis()); + JSONObject updatedOrder = datasourceUpdate(ol, randomDescription); + + int notesAfterUpdate = countNotes(ol); + + assertThat("number of notes", notesAfterUpdate, is(notesBeforeUpdate + 1)); + assertDescription(ol, updatedOrder, randomDescription); + } + + /** Observer does ol.getSalesOrder().getOrderLineList(). Covers issue #32308 */ + @Test + public void observerCanInstantiateObservedObject() throws JSONException { + observerExecutionType = ObserverExecutionType.COUNT_LINES; + + OrderLine ol = pickARandomOrderLine(); + int numberOfLines = ol.getSalesOrder().getOrderLineList().size(); + + String randomDescription = Long.toString(System.currentTimeMillis()); + JSONObject updatedOrder = datasourceUpdate(ol, randomDescription); + + assertDescription(ol, updatedOrder, OrderLineTestObserver.FORCED_DESCRIPTION + numberOfLines); + } + + /** Observer updates order line's header */ + @Test + public void observerCanUpdateParentObject() throws JSONException { + observerExecutionType = ObserverExecutionType.UPDATE_PARENT; + + OrderLine ol = pickARandomOrderLine(); + + String randomDescription = Long.toString(System.currentTimeMillis()); + datasourceUpdate(ol, randomDescription); + + Order order = ol.getSalesOrder(); + + assertThat(order.getEntityName() + " - " + order.getId() + " actual description", + (String) order.get(OrderLine.PROPERTY_DESCRIPTION), + is(OrderLineTestObserver.FORCED_DESCRIPTION)); + } + + private OrderLine pickARandomOrderLine() { + return (OrderLine) OBDal.getInstance().createCriteria(OrderLine.class).setMaxResults(1) + .uniqueResult(); + } + + private JSONObject datasourceUpdate(OrderLine ol, String randomDescription) throws JSONException { + final DataSourceService dataSource = dataSourceServiceProvider + .getDataSource(OrderLine.ENTITY_NAME); + + JSONObject data = new JSONObject(); + data.put(JsonConstants.ID, ol.getId()); + data.put(OrderLine.PROPERTY_DESCRIPTION, randomDescription); + + JSONObject content = new JSONObject(); + content.put(JsonConstants.DATA, data); + + String resp = dataSource.update(new HashMap<String, String>(), content.toString()); + return new JSONObject(resp).getJSONObject(JsonConstants.RESPONSE_RESPONSE) + .getJSONArray(JsonConstants.DATA).getJSONObject(0); + } + + private void assertDescription(BaseOBObject obj, JSONObject updatedOrder, + String expectedDescription) throws JSONException { + OBDal.getInstance().commitAndClose(); + + BaseOBObject refreshedBob = (BaseOBObject) OBDal.getInstance() + .createCriteria(obj.getEntityName()).add(Restrictions.eq(BaseOBObject.ID, obj.getId())) + .uniqueResult(); + assertThat(obj.getEntityName() + " - " + obj.getId() + " response description", + updatedOrder.getString("description"), is(expectedDescription)); + assertThat(obj.getEntityName() + " - " + obj.getId() + " actual description", + (String) refreshedBob.get(OrderLine.PROPERTY_DESCRIPTION), is(expectedDescription)); + } + + private int countNotes(BaseOBObject obj) { + OBContext.setAdminMode(true); + try { + OBCriteria<Note> q = OBDal.getInstance().createCriteria(Note.class); + q.add(Restrictions.eq(Note.PROPERTY_RECORD, obj.getId())); + q.add(Restrictions.eq(Note.PROPERTY_TABLE, + OBDal.getInstance().getProxy(Table.class, obj.getEntity().getTableId()))); + return q.count(); + } finally { + OBContext.restorePreviousMode(); + } + } + + @AfterClass + public static void reset() { + observerExecutionType = ObserverExecutionType.OFF; + } +} diff -r 0f887315d105 -r 64dcdb9cf68b modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/OrderLineTestObserver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/org.openbravo.client.application/src-test/org/openbravo/client/application/test/event/OrderLineTestObserver.java Tue Feb 23 16:37:30 2016 +0100 @@ -0,0 +1,83 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.1 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo SLU + * All portions are Copyright (C) 2016 Openbravo SLU + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ +package org.openbravo.client.application.test.event; + +import javax.enterprise.event.Observes; + +import org.openbravo.base.model.Entity; +import org.openbravo.base.model.ModelProvider; +import org.openbravo.base.provider.OBProvider; +import org.openbravo.client.application.Note; +import org.openbravo.client.kernel.event.EntityPersistenceEventObserver; +import org.openbravo.client.kernel.event.EntityUpdateEvent; +import org.openbravo.dal.service.OBDal; +import org.openbravo.model.ad.datamodel.Table; +import org.openbravo.model.common.order.Order; +import org.openbravo.model.common.order.OrderLine; + +/** + * Test persistence observer used by {@link DatasourceEventObserver} to ensure observer is correctly + * invoked and works fine together with datasource update invocations. + * + * @author alostale + * + */ +public class OrderLineTestObserver extends EntityPersistenceEventObserver { + static final String FORCED_DESCRIPTION = "test description"; + private static Entity[] entities = { ModelProvider.getInstance().getEntity(OrderLine.ENTITY_NAME) }; + + public void onUpdate(@Observes EntityUpdateEvent event) { + if (!isValidEvent(event)) { + return; + } + + switch (DatasourceEventObserver.observerExecutionType) { + case OFF: + return; + case UPDATE_DESCRIPTION: + event.setCurrentState(entities[0].getProperty(OrderLine.PROPERTY_DESCRIPTION), + FORCED_DESCRIPTION); + break; + case CREATE_NOTE: + final OrderLine orderLine = (OrderLine) event.getTargetInstance(); + Note newNote = OBProvider.getInstance().get(Note.class); + newNote.setTable(OBDal.getInstance() + .getProxy(Table.class, orderLine.getEntity().getTableId())); + newNote.setRecord(orderLine.getId()); + newNote.setNote("test"); + OBDal.getInstance().save(newNote); + break; + case COUNT_LINES: + int numOfLines = ((OrderLine) event.getTargetInstance()).getSalesOrder().getOrderLineList() + .size(); + event.setCurrentState(entities[0].getProperty(OrderLine.PROPERTY_DESCRIPTION), + FORCED_DESCRIPTION + numOfLines); + break; + case UPDATE_PARENT: + Order order = ((OrderLine) event.getTargetInstance()).getSalesOrder(); + order.setDescription(FORCED_DESCRIPTION); + break; + } + } + + @Override + protected Entity[] getObservedEntities() { + return entities; + } +} diff -r 0f887315d105 -r 64dcdb9cf68b modules/org.openbravo.service.json/src/org/openbravo/service/json/DefaultJsonDataService.java --- a/modules/org.openbravo.service.json/src/org/openbravo/service/json/DefaultJsonDataService.java Fri Feb 19 13:54:47 2016 +0100 +++ b/modules/org.openbravo.service.json/src/org/openbravo/service/json/DefaultJsonDataService.java Tue Feb 23 16:37:30 2016 +0100 @@ -769,17 +769,19 @@ } } - // refresh the objects from the db as they can have changed - // put the refreshed objects into a new array as we are going to retrieve them using - // OBDal.getInstance().get as performs better than OBDal.getInstance().getSession().refresh - // See issue https://issues.openbravo.com/view.php?id=30308 + // Objects might have been modified in DB through triggers, let's force them to be fetched + // DB again, to do so session is cleared (any possible modification is already persisted by + // previous flush). + // Using OBDal.refresh does not perform well, see issue + // https://issues.openbravo.com/view.php?id=30308 + OBDal.getInstance().getSession().clear(); + ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 _______________________________________________ Openbravo-commits mailing list Openbravo-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openbravo-commits