You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@isis.apache.org by GESCONSULTOR - Óscar Bou <o....@gesconsultor.com> on 2014/04/29 21:14:36 UTC

When finalizing a test - javax.jdo.JDOException: Unexpected error during precommit

Hi to all.

I have an "Asset" entity with inserted() and updated() lifecycle callback methods.

Inside that "updated()" method, I have the following code:

    public void updated() {
        this.insertOrUpdateRelationships();
    }

    public void persisted() {
        this.insertOrUpdateRelationships();
    }

    private void insertOrUpdateRelationships() {
        // Insert/Update Relationships.
        for (final Relationship current : this.relationshipsDerivedFromAnnnotations()) {
            this.wrap(current.getSourceAsset()).addDirectlyImpactedAsset(current.getTargetAsset(), current.getType());
        }
    }


When executed inside a test, the following exception is thrown right after finalizing the Test method (no exceptions thrown while in the Test body):


javax.jdo.JDOException: Unexpected error during precommit
	at org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:596)
	at org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:165)
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
	at org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
	at org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
	at org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
	at org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
	at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
NestedThrowablesStackTrace:
java.lang.RuntimeException: org.apache.isis.core.metamodel.spec.DomainModelException: Callback failed.  Calling UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public void com.xms.framework.architecture.domain.model.Asset.updated()]] on PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString= [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2, class name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:278)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:287)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.postStoreProcessingFor(FrameworkSynchronizer.java:140)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$2.doRun(IsisLifecycleListener.java:95)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$RunnableAbstract.run(IsisLifecycleListener.java:201)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.withLogging(IsisLifecycleListener.java:180)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.postStore(IsisLifecycleListener.java:91)
	at org.datanucleus.api.jdo.JDOCallbackHandler.postStore(JDOCallbackHandler.java:158)
	at org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:5035)
	at org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3652)
	at org.datanucleus.store.fieldmanager.ReachabilityFieldManager.processPersistable(ReachabilityFieldManager.java:69)
	at org.datanucleus.store.fieldmanager.ReachabilityFieldManager.storeObjectField(ReachabilityFieldManager.java:121)
	at org.datanucleus.state.JDOStateManager.providedObjectField(JDOStateManager.java:1269)
	at com.xms.framework.architecture.domain.model.business.extensions.businessservice.BusinessService.jdoProvideField(BusinessService.java)
	at com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.jdoProvideFields(AbstractXMSDomainObject.java)
	at org.datanucleus.state.JDOStateManager.provideFields(JDOStateManager.java:1346)
	at org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3678)
	at org.datanucleus.ExecutionContextImpl.performReachabilityAtCommit(ExecutionContextImpl.java:4437)
	at org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4230)
	at org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:654)
	at org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:379)
	at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:268)
	at org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:98)
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
	at org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
	at org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
	at org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
	at org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
	at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.apache.isis.core.metamodel.spec.DomainModelException: Callback failed.  Calling UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public void com.xms.framework.architecture.domain.model.Asset.updated()]] on PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString= [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2, class name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
	at org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:37)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$2.run(FrameworkSynchronizer.java:176)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:291)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:287)
	at org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:276)
	... 46 more
Caused by: java.lang.IllegalStateException: Transaction already active
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.beginJdoTransaction(DataNucleusObjectStore.java:270)
	at org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.startTransaction(DataNucleusObjectStore.java:256)
	at org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.startTransaction(IsisTransactionManager.java:290)
	at org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:219)
	at org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
	at org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:342)
	at org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:509)
	at org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:236)
	at org.apache.isis.core.wrapper.internal.InvocationHandlerMethodInterceptor.intercept(InvocationHandlerMethodInterceptor.java:37)
	at com.xms.framework.architecture.domain.model.business.extensions.product.Product$$EnhancerByCGLIB$$1432358f.addDirectlyImpactedAsset(<generated>)
	at com.xms.framework.architecture.domain.model.Asset.insertOrUpdateRelationships(Asset.java:847)
	at com.xms.framework.architecture.domain.model.Asset.updated(Asset.java:837)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:50)
	at org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:45)
	at org.apache.isis.core.commons.lang.MethodUtil.invoke(MethodUtil.java:35)
	at org.apache.isis.core.metamodel.adapter.util.AdapterInvokeUtils.invokeAll(AdapterInvokeUtils.java:40)
	at org.apache.isis.core.progmodel.facets.object.callbacks.update.UpdatedCallbackFacetViaMethod.invoke(UpdatedCallbackFacetViaMethod.java:63)
	at org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:35)
	... 50 more



If I change the code to this one (removing the "wrap") it works ok...

    public void updated() {
        this.insertOrUpdateRelationships();
    }

    public void persisted() {
        this.insertOrUpdateRelationships();
    }

    private void insertOrUpdateRelationships() {
        // Insert/Update Relationships.
        for (final Relationship current : this.relationshipsDerivedFromAnnnotations()) {
            current.getSourceAsset().addDirectlyImpactedAsset(current.getTargetAsset(), current.getType());
        }
    }


Seems that it's not properly detected that a transaction is opened. 

Seems there's a hard-to-debug bug deep inside?


Thanks,

Oscar


Re: When finalizing a test - javax.jdo.JDOException: Unexpected error during precommit

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
oh goody...


On 29 April 2014 20:46, GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>wrote:

>
> Hi, Dan.
>
> It makes sense to me ...
>
> I'll send now another one that is the origin I'm becoming crazy... this
> one seems related with DataNucleus.
>
> Thanks,
>
> Oscar
>
>
>
> El 29/04/2014, a las 21:42, Dan Haywood <da...@haywood-associates.co.uk>
> escribió:
>
>
> Hmm, nasty.  I think I can see what's going on (but a code fix will be
> needed).
>
>
> Looking at IsisTransactionManager#executeWithinTransaction() method, I see:
>
>    public <Q> Q executeWithinTransaction(final
> TransactionalClosureWithReturn<Q> closure) {
>        final boolean initiallyInTransaction = inTransaction();
>        if (!initiallyInTransaction) {
>            startTransaction();
>        }
>        try {
>            closure.preExecute();
>            final Q retVal = closure.execute();
>            closure.onSuccess();
>            if (!initiallyInTransaction) {
>                endTransaction();
>            }
>            return retVal;
>        } catch (final RuntimeException ex) {
>            closure.onFailure();
>            if (!initiallyInTransaction) {
>                abortTransaction();
>            }
>            throw ex;
>        }
>    }
>
>    public boolean inTransaction() {
>        return getTransaction() != null &&
> !getTransaction().getState().isComplete();
>    }
>
>
> So presumably inTransaction is returning false, that there is no
> transaction in progress.
>
>
> ~~~
> Looking at IsisTransactionManager#endTransaction(), I see (simplified):
>
>    public synchronized void endTransaction() {
>
>        ...
>
>        transactionLevel--;
>        if (transactionLevel == 0) {
>
>            ...
>
>            // Isis' transaction
>            getTransaction().commit();
>
>            ...
>
>            // JDO transaction
>            transactionalResource.endTransaction();
>
>            ...
>
>        }
>    }
>
>
> Unfortunately IsisTransaction#commit() does too much work:
>
>
>    public synchronized final void commit() {
>
>       ...
>
>       // update services
>
>       doAudit(getChangedObjectProperties());
>
>       final String currentUser =
> getTransactionManager().getAuthenticationSession().getUserName();
>       final Timestamp endTimestamp = Clock.getTimeAsJavaSqlTimestamp();
>
>       publishActionIfRequired(currentUser, endTimestamp);
>       doFlush();
>
>       publishedChangedObjectsIfRequired(currentUser, endTimestamp);
>       doFlush();
>
>       closeServices();
>       doFlush();
>
>
>       // set as comitted
>       setState(State.COMMITTED);
>
>       ...
>    }
>
>
>
> We want the services to be updated prior to the JDO transaction being
> committed, but we want the Isis Transaction's state to be left as in
> progress until after the JDO transaction is committed.
>
>
> ~~~
> Do you agree?  If so, I'll raise a ticket to fix (probably split
> IsisTransaction#commit into a precommit and a postcommit.
>
>
> Thx
> Dan
>
>
>
>
> On 29 April 2014 20:14, GESCONSULTOR - Óscar Bou <o.bou@gesconsultor.com
> >wrote:
>
> Hi to all.
>
> I have an "Asset" entity with inserted() and updated() lifecycle callback
> methods.
>
> Inside that "updated()" method, I have the following code:
>
>    public void updated() {
>        this.insertOrUpdateRelationships();
>    }
>
>    public void persisted() {
>        this.insertOrUpdateRelationships();
>    }
>
>    private void insertOrUpdateRelationships() {
>        // Insert/Update Relationships.
>        for (final Relationship current :
> this.relationshipsDerivedFromAnnnotations()) {
>
>
> this.wrap(current.getSourceAsset()).addDirectlyImpactedAsset(current.getTargetAsset(),
> current.getType());
>        }
>    }
>
>
> When executed inside a test, the following exception is thrown right after
> finalizing the Test method (no exceptions thrown while in the Test body):
>
>
> javax.jdo.JDOException: Unexpected error during precommit
>        at
>
> org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:596)
>        at
> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:165)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>        at
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>        at
>
> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>        at
>
> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>        at
>
> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>        at
>
> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>        at
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>        at
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>        at
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>        at
>
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>        at
>
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>        at
>
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> NestedThrowablesStackTrace:
> java.lang.RuntimeException:
> org.apache.isis.core.metamodel.spec.DomainModelException: Callback failed.
> Calling
> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
> PojoAdapter@6dc5f0ba
> [PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
> class
>
> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:278)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:287)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.postStoreProcessingFor(FrameworkSynchronizer.java:140)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$2.doRun(IsisLifecycleListener.java:95)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$RunnableAbstract.run(IsisLifecycleListener.java:201)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.withLogging(IsisLifecycleListener.java:180)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.postStore(IsisLifecycleListener.java:91)
>        at
>
> org.datanucleus.api.jdo.JDOCallbackHandler.postStore(JDOCallbackHandler.java:158)
>        at
> org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:5035)
>        at
>
> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3652)
>        at
>
> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.processPersistable(ReachabilityFieldManager.java:69)
>        at
>
> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.storeObjectField(ReachabilityFieldManager.java:121)
>        at
>
> org.datanucleus.state.JDOStateManager.providedObjectField(JDOStateManager.java:1269)
>        at
>
> com.xms.framework.architecture.domain.model.business.extensions.businessservice.BusinessService.jdoProvideField(BusinessService.java)
>        at
>
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.jdoProvideFields(AbstractXMSDomainObject.java)
>        at
>
> org.datanucleus.state.JDOStateManager.provideFields(JDOStateManager.java:1346)
>        at
>
> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3678)
>        at
>
> org.datanucleus.ExecutionContextImpl.performReachabilityAtCommit(ExecutionContextImpl.java:4437)
>        at
>
> org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4230)
>        at
>
> org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:654)
>        at
> org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:379)
>        at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:268)
>        at
> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:98)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>        at
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>        at
>
> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>        at
>
> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>        at
>
> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>        at
>
> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>        at
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>        at
>
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>        at
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>        at
>
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>        at
>
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>        at
>
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>        at
>
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> Caused by: org.apache.isis.core.metamodel.spec.DomainModelException:
> Callback failed.  Calling
> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
> PojoAdapter@6dc5f0ba
> [PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
> class
>
> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>        at
>
> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:37)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$2.run(FrameworkSynchronizer.java:176)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:291)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:287)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:276)
>        ... 46 more
> Caused by: java.lang.IllegalStateException: Transaction already active
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.beginJdoTransaction(DataNucleusObjectStore.java:270)
>        at
>
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.startTransaction(DataNucleusObjectStore.java:256)
>        at
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.startTransaction(IsisTransactionManager.java:290)
>        at
>
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:219)
>        at
>
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>        at
>
> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:342)
>        at
>
> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:509)
>        at
>
> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:236)
>        at
>
> org.apache.isis.core.wrapper.internal.InvocationHandlerMethodInterceptor.intercept(InvocationHandlerMethodInterceptor.java:37)
>        at
>
> com.xms.framework.architecture.domain.model.business.extensions.product.Product$$EnhancerByCGLIB$$1432358f.addDirectlyImpactedAsset(<generated>)
>        at
>
> com.xms.framework.architecture.domain.model.Asset.insertOrUpdateRelationships(Asset.java:847)
>        at
> com.xms.framework.architecture.domain.model.Asset.updated(Asset.java:837)
>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>        at
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>        at
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>        at java.lang.reflect.Method.invoke(Method.java:597)
>        at
>
> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:50)
>        at
>
> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:45)
>        at
> org.apache.isis.core.commons.lang.MethodUtil.invoke(MethodUtil.java:35)
>        at
>
> org.apache.isis.core.metamodel.adapter.util.AdapterInvokeUtils.invokeAll(AdapterInvokeUtils.java:40)
>        at
>
> org.apache.isis.core.progmodel.facets.object.callbacks.update.UpdatedCallbackFacetViaMethod.invoke(UpdatedCallbackFacetViaMethod.java:63)
>        at
>
> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:35)
>        ... 50 more
>
>
>
> If I change the code to this one (removing the "wrap") it works ok...
>
>    public void updated() {
>        this.insertOrUpdateRelationships();
>    }
>
>    public void persisted() {
>        this.insertOrUpdateRelationships();
>    }
>
>    private void insertOrUpdateRelationships() {
>        // Insert/Update Relationships.
>        for (final Relationship current :
> this.relationshipsDerivedFromAnnnotations()) {
>
> current.getSourceAsset().addDirectlyImpactedAsset(current.getTargetAsset(),
> current.getType());
>        }
>    }
>
>
> Seems that it's not properly detected that a transaction is opened.
>
> Seems there's a hard-to-debug bug deep inside?
>
>
> Thanks,
>
> Oscar
>
>
>
>
> Óscar Bou Bou
> Responsable de Producto
> Auditor Jefe de Certificación ISO 27001 en BSI
> CISA, CRISC, APMG ISO 20000, ITIL-F
>
>    902 900 231 / 620 267 520
>    http://www.twitter.com/oscarbou
>
>    http://es.linkedin.com/in/oscarbou
>
>    http://www.GesConsultor.com <http://www.gesconsultor.com/>
>
>
>
> Este mensaje y los ficheros anexos son confidenciales. Los mismos
> contienen información reservada que no puede ser difundida. Si usted ha
> recibido este correo por error, tenga la amabilidad de eliminarlo de su
> sistema y avisar al remitente mediante reenvío a su dirección electrónica;
> no deberá copiar el mensaje ni divulgar su contenido a ninguna persona.
> Su dirección de correo electrónico junto a sus datos personales constan en
> un fichero titularidad de Gesdatos Software, S.L. cuya finalidad es la de
> mantener el contacto con Ud. Si quiere saber de qué información disponemos
> de Ud., modificarla, y en su caso, cancelarla, puede hacerlo enviando un
> escrito al efecto, acompañado de una fotocopia de su D.N.I. a la siguiente
> dirección: Gesdatos Software, S.L. , Paseo de la Castellana, 153 bajo -
> 28046 (Madrid), y Avda. Cortes Valencianas num. 50, 1ºC - 46015 (Valencia).
> Asimismo, es su responsabilidad comprobar que este mensaje o sus archivos
> adjuntos no contengan virus informáticos, y en caso que los tuvieran
> eliminarlos.
>
>
>
>
>
>

Re: When finalizing a test - javax.jdo.JDOException: Unexpected error during precommit

Posted by GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>.
Hi, Dan.

It makes sense to me ...

I'll send now another one that is the origin I'm becoming crazy... this one seems related with DataNucleus.

Thanks,

Oscar



El 29/04/2014, a las 21:42, Dan Haywood <da...@haywood-associates.co.uk> escribió:

> Hmm, nasty.  I think I can see what's going on (but a code fix will be
> needed).
> 
> 
> Looking at IsisTransactionManager#executeWithinTransaction() method, I see:
> 
>    public <Q> Q executeWithinTransaction(final
> TransactionalClosureWithReturn<Q> closure) {
>        final boolean initiallyInTransaction = inTransaction();
>        if (!initiallyInTransaction) {
>            startTransaction();
>        }
>        try {
>            closure.preExecute();
>            final Q retVal = closure.execute();
>            closure.onSuccess();
>            if (!initiallyInTransaction) {
>                endTransaction();
>            }
>            return retVal;
>        } catch (final RuntimeException ex) {
>            closure.onFailure();
>            if (!initiallyInTransaction) {
>                abortTransaction();
>            }
>            throw ex;
>        }
>    }
> 
>    public boolean inTransaction() {
>        return getTransaction() != null &&
> !getTransaction().getState().isComplete();
>    }
> 
> 
> So presumably inTransaction is returning false, that there is no
> transaction in progress.
> 
> 
> ~~~
> Looking at IsisTransactionManager#endTransaction(), I see (simplified):
> 
>    public synchronized void endTransaction() {
> 
>        ...
> 
>        transactionLevel--;
>        if (transactionLevel == 0) {
> 
>            ...
> 
>            // Isis' transaction
>            getTransaction().commit();
> 
>            ...
> 
>            // JDO transaction
>            transactionalResource.endTransaction();
> 
>            ...
> 
>        }
>    }
> 
> 
> Unfortunately IsisTransaction#commit() does too much work:
> 
> 
>    public synchronized final void commit() {
> 
>       ...
> 
>       // update services
> 
>       doAudit(getChangedObjectProperties());
> 
>       final String currentUser =
> getTransactionManager().getAuthenticationSession().getUserName();
>       final Timestamp endTimestamp = Clock.getTimeAsJavaSqlTimestamp();
> 
>       publishActionIfRequired(currentUser, endTimestamp);
>       doFlush();
> 
>       publishedChangedObjectsIfRequired(currentUser, endTimestamp);
>       doFlush();
> 
>       closeServices();
>       doFlush();
> 
> 
>       // set as comitted
>       setState(State.COMMITTED);
> 
>       ...
>    }
> 
> 
> 
> We want the services to be updated prior to the JDO transaction being
> committed, but we want the Isis Transaction's state to be left as in
> progress until after the JDO transaction is committed.
> 
> 
> ~~~
> Do you agree?  If so, I'll raise a ticket to fix (probably split
> IsisTransaction#commit into a precommit and a postcommit.
> 
> 
> Thx
> Dan
> 
> 
> 
> 
> On 29 April 2014 20:14, GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>wrote:
> 
>> Hi to all.
>> 
>> I have an "Asset" entity with inserted() and updated() lifecycle callback
>> methods.
>> 
>> Inside that "updated()" method, I have the following code:
>> 
>>    public void updated() {
>>        this.insertOrUpdateRelationships();
>>    }
>> 
>>    public void persisted() {
>>        this.insertOrUpdateRelationships();
>>    }
>> 
>>    private void insertOrUpdateRelationships() {
>>        // Insert/Update Relationships.
>>        for (final Relationship current :
>> this.relationshipsDerivedFromAnnnotations()) {
>> 
>> this.wrap(current.getSourceAsset()).addDirectlyImpactedAsset(current.getTargetAsset(),
>> current.getType());
>>        }
>>    }
>> 
>> 
>> When executed inside a test, the following exception is thrown right after
>> finalizing the Test method (no exceptions thrown while in the Test body):
>> 
>> 
>> javax.jdo.JDOException: Unexpected error during precommit
>>        at
>> org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:596)
>>        at
>> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:165)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>>        at
>> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>>        at
>> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>>        at
>> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>>        at
>> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>>        at
>> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>>        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>>        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>>        at
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>>        at
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>>        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>>        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>>        at
>> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>>        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>>        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>>        at
>> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>>        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>>        at
>> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>>        at
>> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
>> NestedThrowablesStackTrace:
>> java.lang.RuntimeException:
>> org.apache.isis.core.metamodel.spec.DomainModelException: Callback failed.
>> Calling
>> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
>> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
>> PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
>> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
>> class
>> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:278)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:287)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.postStoreProcessingFor(FrameworkSynchronizer.java:140)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$2.doRun(IsisLifecycleListener.java:95)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$RunnableAbstract.run(IsisLifecycleListener.java:201)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.withLogging(IsisLifecycleListener.java:180)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.postStore(IsisLifecycleListener.java:91)
>>        at
>> org.datanucleus.api.jdo.JDOCallbackHandler.postStore(JDOCallbackHandler.java:158)
>>        at
>> org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:5035)
>>        at
>> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3652)
>>        at
>> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.processPersistable(ReachabilityFieldManager.java:69)
>>        at
>> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.storeObjectField(ReachabilityFieldManager.java:121)
>>        at
>> org.datanucleus.state.JDOStateManager.providedObjectField(JDOStateManager.java:1269)
>>        at
>> com.xms.framework.architecture.domain.model.business.extensions.businessservice.BusinessService.jdoProvideField(BusinessService.java)
>>        at
>> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.jdoProvideFields(AbstractXMSDomainObject.java)
>>        at
>> org.datanucleus.state.JDOStateManager.provideFields(JDOStateManager.java:1346)
>>        at
>> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3678)
>>        at
>> org.datanucleus.ExecutionContextImpl.performReachabilityAtCommit(ExecutionContextImpl.java:4437)
>>        at
>> org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4230)
>>        at
>> org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:654)
>>        at
>> org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:379)
>>        at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:268)
>>        at
>> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:98)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>>        at
>> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>>        at
>> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>>        at
>> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>>        at
>> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>>        at
>> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>>        at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>>        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>>        at
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>>        at
>> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>>        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>>        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>>        at
>> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>>        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>>        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>>        at
>> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>>        at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>>        at
>> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>>        at
>> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>>        at
>> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
>> Caused by: org.apache.isis.core.metamodel.spec.DomainModelException:
>> Callback failed.  Calling
>> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
>> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
>> PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
>> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
>> class
>> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>>        at
>> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:37)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$2.run(FrameworkSynchronizer.java:176)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:291)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:287)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:276)
>>        ... 46 more
>> Caused by: java.lang.IllegalStateException: Transaction already active
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.beginJdoTransaction(DataNucleusObjectStore.java:270)
>>        at
>> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.startTransaction(DataNucleusObjectStore.java:256)
>>        at
>> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.startTransaction(IsisTransactionManager.java:290)
>>        at
>> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:219)
>>        at
>> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>>        at
>> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:342)
>>        at
>> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:509)
>>        at
>> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:236)
>>        at
>> org.apache.isis.core.wrapper.internal.InvocationHandlerMethodInterceptor.intercept(InvocationHandlerMethodInterceptor.java:37)
>>        at
>> com.xms.framework.architecture.domain.model.business.extensions.product.Product$$EnhancerByCGLIB$$1432358f.addDirectlyImpactedAsset(<generated>)
>>        at
>> com.xms.framework.architecture.domain.model.Asset.insertOrUpdateRelationships(Asset.java:847)
>>        at
>> com.xms.framework.architecture.domain.model.Asset.updated(Asset.java:837)
>>        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>        at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>        at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>        at java.lang.reflect.Method.invoke(Method.java:597)
>>        at
>> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:50)
>>        at
>> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:45)
>>        at
>> org.apache.isis.core.commons.lang.MethodUtil.invoke(MethodUtil.java:35)
>>        at
>> org.apache.isis.core.metamodel.adapter.util.AdapterInvokeUtils.invokeAll(AdapterInvokeUtils.java:40)
>>        at
>> org.apache.isis.core.progmodel.facets.object.callbacks.update.UpdatedCallbackFacetViaMethod.invoke(UpdatedCallbackFacetViaMethod.java:63)
>>        at
>> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:35)
>>        ... 50 more
>> 
>> 
>> 
>> If I change the code to this one (removing the "wrap") it works ok...
>> 
>>    public void updated() {
>>        this.insertOrUpdateRelationships();
>>    }
>> 
>>    public void persisted() {
>>        this.insertOrUpdateRelationships();
>>    }
>> 
>>    private void insertOrUpdateRelationships() {
>>        // Insert/Update Relationships.
>>        for (final Relationship current :
>> this.relationshipsDerivedFromAnnnotations()) {
>> 
>> current.getSourceAsset().addDirectlyImpactedAsset(current.getTargetAsset(),
>> current.getType());
>>        }
>>    }
>> 
>> 
>> Seems that it's not properly detected that a transaction is opened.
>> 
>> Seems there's a hard-to-debug bug deep inside?
>> 
>> 
>> Thanks,
>> 
>> Oscar
>> 
>> 


Óscar Bou Bou
Responsable de Producto
Auditor Jefe de Certificación ISO 27001 en BSI
CISA, CRISC, APMG ISO 20000, ITIL-F

   902 900 231 / 620 267 520
   http://www.twitter.com/oscarbou

   http://es.linkedin.com/in/oscarbou

   http://www.GesConsultor.com 




Este mensaje y los ficheros anexos son confidenciales. Los mismos contienen información reservada que no puede ser difundida. Si usted ha recibido este correo por error, tenga la amabilidad de eliminarlo de su sistema y avisar al remitente mediante reenvío a su dirección electrónica; no deberá copiar el mensaje ni divulgar su contenido a ninguna persona.
Su dirección de correo electrónico junto a sus datos personales constan en un fichero titularidad de Gesdatos Software, S.L. cuya finalidad es la de mantener el contacto con Ud. Si quiere saber de qué información disponemos de Ud., modificarla, y en su caso, cancelarla, puede hacerlo enviando un escrito al efecto, acompañado de una fotocopia de su D.N.I. a la siguiente dirección: Gesdatos Software, S.L. , Paseo de la Castellana, 153 bajo - 28046 (Madrid), y Avda. Cortes Valencianas num. 50, 1ºC - 46015 (Valencia). Asimismo, es su responsabilidad comprobar que este mensaje o sus archivos adjuntos no contengan virus informáticos, y en caso que los tuvieran eliminarlos.






Re: When finalizing a test - javax.jdo.JDOException: Unexpected error during precommit

Posted by Dan Haywood <da...@haywood-associates.co.uk>.
Hmm, nasty.  I think I can see what's going on (but a code fix will be
needed).


Looking at IsisTransactionManager#executeWithinTransaction() method, I see:

    public <Q> Q executeWithinTransaction(final
TransactionalClosureWithReturn<Q> closure) {
        final boolean initiallyInTransaction = inTransaction();
        if (!initiallyInTransaction) {
            startTransaction();
        }
        try {
            closure.preExecute();
            final Q retVal = closure.execute();
            closure.onSuccess();
            if (!initiallyInTransaction) {
                endTransaction();
            }
            return retVal;
        } catch (final RuntimeException ex) {
            closure.onFailure();
            if (!initiallyInTransaction) {
                abortTransaction();
            }
            throw ex;
        }
    }

    public boolean inTransaction() {
        return getTransaction() != null &&
!getTransaction().getState().isComplete();
    }


So presumably inTransaction is returning false, that there is no
transaction in progress.


~~~
Looking at IsisTransactionManager#endTransaction(), I see (simplified):

    public synchronized void endTransaction() {

        ...

        transactionLevel--;
        if (transactionLevel == 0) {

            ...

            // Isis' transaction
            getTransaction().commit();

            ...

            // JDO transaction
            transactionalResource.endTransaction();

            ...

        }
    }


Unfortunately IsisTransaction#commit() does too much work:


    public synchronized final void commit() {

       ...

       // update services

       doAudit(getChangedObjectProperties());

       final String currentUser =
getTransactionManager().getAuthenticationSession().getUserName();
       final Timestamp endTimestamp = Clock.getTimeAsJavaSqlTimestamp();

       publishActionIfRequired(currentUser, endTimestamp);
       doFlush();

       publishedChangedObjectsIfRequired(currentUser, endTimestamp);
       doFlush();

       closeServices();
       doFlush();


       // set as comitted
       setState(State.COMMITTED);

       ...
    }



We want the services to be updated prior to the JDO transaction being
committed, but we want the Isis Transaction's state to be left as in
progress until after the JDO transaction is committed.


~~~
Do you agree?  If so, I'll raise a ticket to fix (probably split
IsisTransaction#commit into a precommit and a postcommit.


Thx
Dan




On 29 April 2014 20:14, GESCONSULTOR - Óscar Bou <o....@gesconsultor.com>wrote:

> Hi to all.
>
> I have an "Asset" entity with inserted() and updated() lifecycle callback
> methods.
>
> Inside that "updated()" method, I have the following code:
>
>     public void updated() {
>         this.insertOrUpdateRelationships();
>     }
>
>     public void persisted() {
>         this.insertOrUpdateRelationships();
>     }
>
>     private void insertOrUpdateRelationships() {
>         // Insert/Update Relationships.
>         for (final Relationship current :
> this.relationshipsDerivedFromAnnnotations()) {
>
> this.wrap(current.getSourceAsset()).addDirectlyImpactedAsset(current.getTargetAsset(),
> current.getType());
>         }
>     }
>
>
> When executed inside a test, the following exception is thrown right after
> finalizing the Test method (no exceptions thrown while in the Test body):
>
>
> javax.jdo.JDOException: Unexpected error during precommit
>         at
> org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:596)
>         at
> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:165)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>         at
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>         at
> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>         at
> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>         at
> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>         at
> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>         at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>         at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>         at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>         at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>         at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>         at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>         at
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>         at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>         at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>         at
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>         at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>         at
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>         at
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> NestedThrowablesStackTrace:
> java.lang.RuntimeException:
> org.apache.isis.core.metamodel.spec.DomainModelException: Callback failed.
>  Calling
> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
> PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
> class
> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:278)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:287)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.postStoreProcessingFor(FrameworkSynchronizer.java:140)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$2.doRun(IsisLifecycleListener.java:95)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener$RunnableAbstract.run(IsisLifecycleListener.java:201)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.withLogging(IsisLifecycleListener.java:180)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.IsisLifecycleListener.postStore(IsisLifecycleListener.java:91)
>         at
> org.datanucleus.api.jdo.JDOCallbackHandler.postStore(JDOCallbackHandler.java:158)
>         at
> org.datanucleus.state.JDOStateManager.flush(JDOStateManager.java:5035)
>         at
> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3652)
>         at
> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.processPersistable(ReachabilityFieldManager.java:69)
>         at
> org.datanucleus.store.fieldmanager.ReachabilityFieldManager.storeObjectField(ReachabilityFieldManager.java:121)
>         at
> org.datanucleus.state.JDOStateManager.providedObjectField(JDOStateManager.java:1269)
>         at
> com.xms.framework.architecture.domain.model.business.extensions.businessservice.BusinessService.jdoProvideField(BusinessService.java)
>         at
> com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.jdoProvideFields(AbstractXMSDomainObject.java)
>         at
> org.datanucleus.state.JDOStateManager.provideFields(JDOStateManager.java:1346)
>         at
> org.datanucleus.state.JDOStateManager.runReachability(JDOStateManager.java:3678)
>         at
> org.datanucleus.ExecutionContextImpl.performReachabilityAtCommit(ExecutionContextImpl.java:4437)
>         at
> org.datanucleus.ExecutionContextImpl.preCommit(ExecutionContextImpl.java:4230)
>         at
> org.datanucleus.ExecutionContextImpl.transactionPreCommit(ExecutionContextImpl.java:654)
>         at
> org.datanucleus.TransactionImpl.internalPreCommit(TransactionImpl.java:379)
>         at org.datanucleus.TransactionImpl.commit(TransactionImpl.java:268)
>         at
> org.datanucleus.api.jdo.JDOTransaction.commit(JDOTransaction.java:98)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.commitJdoTransaction(DataNucleusObjectStore.java:278)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.endTransaction(DataNucleusObjectStore.java:260)
>         at
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:406)
>         at
> org.apache.isis.core.integtestsupport.IsisSystemForTest.commitTran(IsisSystemForTest.java:610)
>         at
> org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:164)
>         at
> org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:149)
>         at
> org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
>         at org.junit.rules.RunRules.evaluate(RunRules.java:20)
>         at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
>         at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
>         at
> org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
>         at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
>         at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
>         at
> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
>         at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
>         at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
>         at
> org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
>         at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
>         at
> org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
>         at
> org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
>         at
> org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> Caused by: org.apache.isis.core.metamodel.spec.DomainModelException:
> Callback failed.  Calling
> UpdatedCallbackFacetViaMethod[type=UpdatedCallbackFacet,methods=[public
> void com.xms.framework.architecture.domain.model.Asset.updated()]] on
> PojoAdapter@6dc5f0ba[PR~:com.xms.framework.architecture.domain.model.business.extensions.product.Product:L_0,specification=Product,version=null,pojo-toString=
> [name=Product,  [tenantId=301, [id=2ED03E03-2894-485B-8491-CE88230788B2,
> class
> name=com.xms.framework.architecture.domain.model.business.extensions.product.Product]]],pojo-hash=#64164b49]
>         at
> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:37)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$2.run(FrameworkSynchronizer.java:176)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:291)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer$7.call(FrameworkSynchronizer.java:287)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.persistence.FrameworkSynchronizer.withLogging(FrameworkSynchronizer.java:276)
>         ... 46 more
> Caused by: java.lang.IllegalStateException: Transaction already active
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.beginJdoTransaction(DataNucleusObjectStore.java:270)
>         at
> org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.startTransaction(DataNucleusObjectStore.java:256)
>         at
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.startTransaction(IsisTransactionManager.java:290)
>         at
> org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:219)
>         at
> org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54)
>         at
> org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:342)
>         at
> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:509)
>         at
> org.apache.isis.core.wrapper.internal.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:236)
>         at
> org.apache.isis.core.wrapper.internal.InvocationHandlerMethodInterceptor.intercept(InvocationHandlerMethodInterceptor.java:37)
>         at
> com.xms.framework.architecture.domain.model.business.extensions.product.Product$$EnhancerByCGLIB$$1432358f.addDirectlyImpactedAsset(<generated>)
>         at
> com.xms.framework.architecture.domain.model.Asset.insertOrUpdateRelationships(Asset.java:847)
>         at
> com.xms.framework.architecture.domain.model.Asset.updated(Asset.java:837)
>         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>         at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>         at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>         at java.lang.reflect.Method.invoke(Method.java:597)
>         at
> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:50)
>         at
> org.apache.isis.core.commons.lang.MethodExtensions.invoke(MethodExtensions.java:45)
>         at
> org.apache.isis.core.commons.lang.MethodUtil.invoke(MethodUtil.java:35)
>         at
> org.apache.isis.core.metamodel.adapter.util.AdapterInvokeUtils.invokeAll(AdapterInvokeUtils.java:40)
>         at
> org.apache.isis.core.progmodel.facets.object.callbacks.update.UpdatedCallbackFacetViaMethod.invoke(UpdatedCallbackFacetViaMethod.java:63)
>         at
> org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils.callCallback(CallbackUtils.java:35)
>         ... 50 more
>
>
>
> If I change the code to this one (removing the "wrap") it works ok...
>
>     public void updated() {
>         this.insertOrUpdateRelationships();
>     }
>
>     public void persisted() {
>         this.insertOrUpdateRelationships();
>     }
>
>     private void insertOrUpdateRelationships() {
>         // Insert/Update Relationships.
>         for (final Relationship current :
> this.relationshipsDerivedFromAnnnotations()) {
>
> current.getSourceAsset().addDirectlyImpactedAsset(current.getTargetAsset(),
> current.getType());
>         }
>     }
>
>
> Seems that it's not properly detected that a transaction is opened.
>
> Seems there's a hard-to-debug bug deep inside?
>
>
> Thanks,
>
> Oscar
>
>