Pax Exam synchronisation issues - java

I am using Pax Exam to perform integration tests to my OSGi application. The application is comprised of a number of different bundles which I deploy to the test container using a ConfigurationFactory as follows:
public class TestConfigurationFactory implements ConfigurationFactory {
#Override
public Option[] createConfiguration() {
return options(
karafDistributionConfiguration()
.frameworkUrl(
maven().groupId("org.apache.karaf")
.artifactId("apache-karaf")
.version("3.0.1").type("tar.gz"))
.unpackDirectory(new File("target/exam"))
.useDeployFolder(false),
keepRuntimeFolder(),
// Karaf (own) features.
KarafDistributionOption.features(
maven().groupId("org.apache.karaf.features")
.artifactId("standard").classifier("features")
.version("3.0.1").type("xml"), "scr"),
// CXF features.
KarafDistributionOption.features(maven()
.groupId("org.apache.cxf.karaf")
.artifactId("apache-cxf").version("2.7.9")
.classifier("features").type("xml")),
// Application features.
KarafDistributionOption.features(
maven().groupId("com.me.project")
.artifactId("my-karaf-features")
.version("1.0.0-SNAPSHOT")
.classifier("features").type("xml"), "my-feature"));
}
}
This works great and I can then write test methods to test my application, I have however the following problem which I understand is in essence a synchronisation issue. One of the bundles I deploy as part of my-feature has an EventHandler which listens for bundles being started and writes some information about each started bundle to the DB. This I assume is something that takes place asynchronously to the execution of my test method. After my test method is executed I can therefore see the following exception in my test output for a query that takes place in my EventHandler:
<openjpa-2.3.0-r422266:1540826 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Failed to execute query "XXX". Check the query syntax for correctness. See nested exception for details.
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:872)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:794)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:542)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:275)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:291)[90:org.apache.openjpa:2.3.0]
...
Caused by: org.osgi.service.blueprint.container.ServiceUnavailableException: The Blueprint container is being or has been destroyed: (objectClass=java
x.transaction.TransactionManager)
at org.apache.aries.blueprint.container.ReferenceRecipe.getService(ReferenceRecipe.java:240)[19:org.apache.aries.blueprint.core:1.4.0]
at org.apache.aries.blueprint.container.ReferenceRecipe.access$000(ReferenceRecipe.java:55)[19:org.apache.aries.blueprint.core:1.4.0]
at org.apache.aries.blueprint.container.ReferenceRecipe$ServiceDispatcher.call(ReferenceRecipe.java:298)[19:org.apache.aries.blueprint.core:1.
4.0]
at Proxy8da13f59_1943_4e85_b276_b44a20a26ceb.getTransaction(Unknown Source)[:]
at org.apache.commons.dbcp.managed.TransactionRegistry.getActiveTransactionContext(TransactionRegistry.java:91)[76:org.apache.servicemix.bundl
es.commons-dbcp:1.4.0.3]
at org.apache.commons.dbcp.managed.ManagedConnection.updateTransactionStatus(ManagedConnection.java:67)[76:org.apache.servicemix.bundles.commo
ns-dbcp:1.4.0.3]
at org.apache.commons.dbcp.managed.ManagedConnection.checkOpen(ManagedConnection.java:60)[76:org.apache.servicemix.bundles.commons-dbcp:1.4.0.
3]
at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:293)[76:org.apache.servicemix.bundles.commons-dbcp:
1.4.0.3]
at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:135)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection.prepareStatement(LoggingConnectionDecorator.java:248)[90:org.apach
e.openjpa:2.3.0]
at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:133)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.lib.jdbc.ConfiguringConnectionDecorator$ConfiguringConnection.prepareStatement(ConfiguringConnectionDecorator.java:140)[
90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:133)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$RefCountConnection.prepareStatement(JDBCStoreManager.java:1643)[90:org.apache.openjpa:2.3.0
]
at org.apache.openjpa.lib.jdbc.DelegatingConnection.prepareStatement(DelegatingConnection.java:122)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:508)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:488)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.jdbc.sql.SQLBuffer.prepareStatement(SQLBuffer.java:477)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.jdbc.kernel.PreparedSQLStoreQuery$PreparedSQLExecutor.executeQuery(PreparedSQLStoreQuery.java:110)[90:org.apache.openjpa
:2.3.0]
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:1005)[90:org.apache.openjpa:2.3.0]
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:863)[90:org.apache.openjpa:2.3.0]
... 15 more
My understanding is that this exception is due to the fact that at the moment my test methods are executed and Pax Exam starts shuting down the container my EventHandler is still handling bundles, happily reading and writing from the DB, when the TransactionManager is swept under its feet. So my question is, is there a way to force Pax Exam to wait for my EventHandler to finish its processing before shutting down Karaf?

It seems you need to establish a semaphore before the test method returns. The semaphore would get released by the EventHandler after meeting a termination condition.
Other than that, if you're on karaf 2.x then maybe it's some blueprint synchronization issue.

Related

UserTransaction jndi lookup failed when using CompletableFuture

I have a code which does context lookup to get UserTransaction JNDI as ctx.lookup("java:comp/UserTransaction").
When I run this code without using CompletableFuture, it works as expected.
When working with CompletableFuture in async thread, it gives exception saying jndi lookup failed.
I tried to check if I can get the required JNDI from global scope, but no luck.
CompletableFutures often run on the JDK's ForkJoinPool rather than application server managed threads, and so lack access to services provided by the application server. MicroProfile Context Propagation (available in Liberty) solves this problem by giving you a way to create CompletableFutures that run on the Liberty thread pool and with access to application component context.
In server.xml,
<featureManager>
<feature>mpContextPropagation-1.2</feature> <!-- 1.0 is also valid -->
<feature>jndi-1.0</feature>
<feature>jdbc-4.2</feature> <!-- or some other feature that participates in transactions -->
... other features
</featureManager>
In your application,
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.context.ThreadContext;
...
ManagedExecutor executor = ManagedExecutor.builder()
.propagate(ThreadContext.APPLICATION)
.build();
CompletableFuture<?> f = executor.supplyAsync(() -> {
UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
...
});
...
executor.shutdown();
If you don't want to construct a new ManagedExecutor, Liberty will also let you cast an EE Concurrency ManagedExecutorService to ManagedExecutor and use that. For example,
ManagedExecutor executor = InitialContext.doLookup("java:comp/DefaultManagedExecutor");
It should also be noted that with a ManagedExecutor, the application context is made available to dependent stages as well as the initial stage, allowing you to perform the lookup in a dependent stage such as the following if you prefer:
executor.supplyAsync(supplier).thenApplyAsync(v -> {
UserTransaction tx = InitialContext.doLookup("java:comp/UserTransaction");
...
});
The problem seems to be that the JNDI context is not propagated to the async thread, so when the CompletionStage attempts to execute the JNDI lookup, it has no context, so it doesn't know which component it is in and thus fails.
There is a very detailed explanation of context propagation and how to do it effectively in Open Liberty (which is the underlying product for WebSphere Liberty) at https://openliberty.io/docs/21.0.0.8/microprofile-context-propagation.html - I'd highly suggest reading it.
Certain Java/Jakarta/MicroProfile APIs will allow you to specify the async service (ExecutorService) to use for the async operation. If possible, you can pass it an instance of ManagedExecutorService which should propagate contexts (like JNDI, security, classloading, etc.) to the async thread. Otherwise, you may need to specify the managed executor service when constructing your CompletionStage.

Mutation SURVIVED but runtime exception was thrown in the code under test

I have a Class calling a super-Method for registering a Bean Mapper. Other methods Use a super-Method for mapping Beans which relies on having the responsible Bean Mapper registered before.
If a Bean is being mapped without a matching registered Mapper, a custom Runtime-Exception is thrown.
When I remove the registration of the Bean-Mapper myself, 240 Tests are failing because the called super.map() method raises a Runtime-Exception.
But PIT tells me: SURVIVED.
removed call to org/laladev/moneyjinn/businesslogic/service/impl/AbstractService::registerBeanMapper → SURVIVED
Why?
Yes - At least one of the "Error"-Tests is listed as an examinded Test.
When I remove the line myself and execute all of my Tests, plenty of them are counted as Errors with:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is Mapper undefined!
It is a Spring Boot App and the container is fired up automatically during unittesting by Spring for all my "end user tests" (JSON/REST in+out) which are something like 95% of all my tests.

WTRN0062E: An illegal attempt to use multiple resources that have only one-phase capability has occurred within a global transaction

In webspehere App Server(WAS)version 8,getting the below error with Non-XA datasource.I have changed to XA datasource to test but giving different error as connection timeout/not available.Below is the error for Non-XA Datasource:
RegisteredRes E WTRN0062E: An illegal attempt to use multiple resources that have only one-phase capability has occurred within a global transaction.
LocalTransact E J2CA0030E: Method enlist caught com.ibm.ws.Transaction.IllegalResourceIn2PCTransactionException: Illegal attempt to enlist multiple 1PC XAResources
at com.ibm.ws.tx.jta.RegisteredResources.enlistResource(RegisteredResources.java:870)
Interesting part is it is working fine in WAS6.Really appreciate if anyone can suggest something?
This error is indicating that you are using at least two transactional resources (databases,queues, SAP managed connections,... ) inside a global transaction.
Within a globlal transaction, all resources must support Two Phase Commits (or at least, all except one, if last participant support is enabled)
If you are using QueueConnectionFactories, there are a checkbox to enable XA. Regarding datasources, you should use the XA driver and so on.
I would double check all the resources to assure all of them are configured to support 2PC.
Regards

Client's Transaction Aborted when accessing two databases

I have a propertiesbean which gives me SqlSessions.
This bean is annotated with all this jazz # the class level
#Singleton
#LocalBean
#Startup
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
i also have this
public SqlSessionFactory getSqlSessionFactory(ConnTypes connType) {...}
which returns the SqlSession you want.
I have two databases. One is a mysql instance and the other one isn't (lets call it db2).
When I run the project locally everything is fine. Both databases are accessed with no problem.
When I run the project on our test server it starts to throw a Client Transaction aborted error. I've done a fair amount of research on this and it seems like people get these exceptions when there is a problem with a database query or some database access. The entire transaction is then marked as rollback and this exception is thrown (at least that's what i've read)
It looks to me like it throws an XA-Resource error right before the first time it throws the client's transaction aborted error. I know that you can get those when your bean tries to access another session. I've seen this error before when running locally and trying to maintain connections to both databases in one method.
Could it be that my singleton properties bean, which accesses both databases, gets into a weird transactional state trying to return a mysql session in one thread and a db2 session in the other?

JPA issue on Websphere -- works fine on Tomcat

I have a Spring 3 application using openJPA as persistence management, following section works fine in STS/Tomcat
#Transactional
createBalance(){
.....
Balance balance = new SummaryBalance();
balance.setName(name);
balance.setCurrency(currency);
balance.setClosingTimestamp(closingTime);
balance.setStatus(BalanceStatus.OPEN);
balance.persist(); // persist !!
......
balance.setCloseAmount(amount);
balance.setLastUpdateTimestamp(now);
}
However, when deploying same code in websphere 7, the closeAmount and lastUpdate does not update(both fields in DB didn't get update but from log both field can return values by their getter) then show up as null, but changes to other fields before persist() do take effect when the method finished. So I bet when the method finishing WS didn't flush the changes towards these fields.
I thought the JPA(regardless of vendor) should keep the balance entity object managed after persist() and flush the object after the method is finished with later changes. Turns out Websphere 7 doesn't make it. Even I put a merge() method
balance.setCloseAmount(amount);
balance.setLastUpdateTimestamp(now);
balance.merge();
still does not help.
Questions:
OpenJPA has already been included as dependencies in the deployment, but why still websphere need to involve with the JPA management?
How to solve the problem?
Thanks in advance.
I'm not sure that this exactly answers your question, but I think you should do some reconfiguration to use WebSphere capabilities, please check Spring 3.1 documentation
11.8.1 IBM WebSphere
On WebSphere 6.1.0.9 and above, the recommended Spring JTA transaction
manager to use is WebSphereUowTransactionManager. This special adapter
leverages IBM's UOWManager API, which is available in WebSphere
Application Server 6.0.2.19 and later and 6.1.0.9 and later. With this
adapter, Spring-driven transaction suspension (suspend/resume as
initiated by PROPAGATION_REQUIRES_NEW) is officially supported by IBM!
and
11.9.1 Use of the wrong transaction manager for a specific DataSource
Use the correct PlatformTransactionManager implementation based on
your choice of transactional technologies and requirements. Used
properly, the Spring Framework merely provides a straightforward and
portable abstraction. If you are using global transactions, you must
use the org.springframework.transaction.jta.JtaTransactionManager
class (or an application server-specific subclass of it) for all your
transactional operations. Otherwise the transaction infrastructure
attempts to perform local transactions on resources such as container
DataSource instances. Such local transactions do not make sense, and a
good application server treats them as errors.
Figure out a solution myself with guess work. Simply just place the persist() by the end of the whole method body.
#Transactional
createBalance(){
.....
Balance balance = new SummaryBalance();
balance.setName(name);
balance.setCurrency(currency);
balance.setClosingTimestamp(closingTime);
balance.setStatus(BalanceStatus.OPEN);
......
balance.setCloseAmount(amount);
balance.setLastUpdateTimestamp(now);
......
balance.persist(); // persist !!
}
That can make sure every fields are set before the method finished.
Both merge() and explicit flush() won't do the job but only with above compromise. Still not quite sure about the official work around....
I will keep this thread open for any new thinking come in :)

Categories