OSGI Integration testing, Pax Exam probe executing tests before container bundles start - osgi

I'm currently trying to write an OSGI integration tests using PAX-EXAM+KARAF and faced a problem that pax exam trying to execute test methods before dependent bundles are actually started/initialized in container. What's strange, sometimes test succeeds, and in that case all bundles/contexts are started and logged, but the majority of times it does not. Delays in methods won't help:( Anyone could help with this issue?
I'm using
PAX-EXAM 2.6.0,
org.apache.karaf.tooling.exam.container 2.3.0,
apache-karaf 2.3.0.
Code:
#Inject
BundleContext bundleContext;
#Inject
EntityManagerFactoryService entityManagerFactoryService;//Service exposed trough OSGI
protected EntityManager entityManager;
#Before
public void init() throws InterruptedException {
entityManager = entityManagerFactoryService.getEntityManagerFactory().createEntityManager();
}
#Configuration
public static Option[] configuration() throws Exception {
return new Option[] {
karafDistributionConfiguration().frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf").type("zip").versionAsInProject())
.karafVersion("2.3.0").name("Apache Karaf"),
mavenBundle("com.google.guava", "guava", "13.0.1").startLevel(30),
mavenBundle("com.mysql.jdbc", "com.springsource.com.mysql.jdbc", "5.1.6").startLevel(30),
mavenBundle("javax.persistence", "com.springsource.javax.persistence", "2.0.0").startLevel(30),
mavenBundle("org.apache.commons", "com.springsource.org.apache.commons.lang", "2.6.0").startLevel(30),
...the rest of bundles
junitBundles(), };
Test method:
#Test
public void contextNotNull() {
Assert.assertNotNull(entityManagerFactoryService);
}
The log:
java.lang.ClassNotFoundException: com.startjg.crp.core.dao.service.EntityManagerFactoryService not found by PAXEXAM-PROBE-749fa717-8bdc-4d9a-9803-bdaf6d4edac0 [144]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Full log:
https://www.dropbox.com/s/v12r15sbmtu9svp/log.txt
Also tried with no luck:
protected <T> Object getService(Class<T> serviceClass) {
int maxCount = 5;
int delay = 5000;
for (int i = 0; i <= maxCount; i++) {
if (bundleContext.getServiceReference(serviceClass) != null) {
ServiceReference<T> serviceReference = bundleContext.getServiceReference(serviceClass);
return bundleContext.getService(serviceReference);
} else {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return null;
}
#Before
public void init() throws InterruptedException {
EntityManagerFactoryService emfs = (EntityManagerFactoryService) getService(EntityManagerFactoryService.class);
entityManager = entityManagerFactoryService.getEntityManagerFactory().createEntityManager();
}

Are you sure your EntityManager is working and available as Service?
You are most probably missing some dependencies, that's why your bundle containing the service isn't fully started.

The current pax exam 3.3.0 now fully supports karaf as a container. The former karaf exam code now fully moved to pax exam.

Related

How can I shutdown Spring boot thread pool project amicably which is 24x7 running

I have created spring boot thread pool project which has thread that needs to run 24x7 once spawned but when I need to stop the app in server for some maintenance it should shutdown after completing its current task and not taking up any new task.
My code for the same is:
Config class
#Configuration
public class ThreadConfig {
#Bean
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor executorPool = new ThreadPoolTaskExecutor();
executorPool.setCorePoolSize(10);
executorPool.setMaxPoolSize(20);
executorPool.setQueueCapacity(10);
executorPool.setWaitForTasksToCompleteOnShutdown(true);
executorPool.setAwaitTerminationSeconds(60);
executorPool.initialize();
return executorPool;
}
}
Runnable class
#Component
#Scope("prototype")
public class DataMigration implements Runnable {
String name;
private boolean run=true;
public DataMigration(String name) {
this.name = name;
}
#Override
public void run() {
while(run){
System.out.println(Thread.currentThread().getName()+" Start Thread = "+name);
processCommand();
System.out.println(Thread.currentThread().getName()+" End Thread = "+name);
if(Thread.currentThread().isInterrupted()){
System.out.println("Thread Is Interrupted");
break;
}
}
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void shutdown(){
this.run = false;
}
}
Main class:
#SpringBootApplication
public class DataMigrationPocApplication implements CommandLineRunner{
#Autowired
private ThreadPoolTaskExecutor taskExecutor;
public static void main(String[] args) {
SpringApplication.run(DataMigrationPocApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
for(int i = 1; i<=20 ; i++){
taskExecutor.execute(new DataMigration("Task " + i));
}
for (;;) {
int count = taskExecutor.getActiveCount();
System.out.println("Active Threads : " + count);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 0) {
taskExecutor.shutdown();
break;
}
}
System.out.println("Finished all threads");
}
}
I need help to understand if I need to stop my spring boot application it should stop all the 20 threads running which runs (24x7) otherwise after completing there current loop in while loop and exit.
I would propose couple of changes in this code to resolve the problem
1) since in your POC processCommand calls Thread.sleep, when you shutdown the executor and it interrupts workers InterruptedException get called but is almost ignored in your code. After that there is if(Thread.currentThread().isInterrupted()) check which will return false for the reason above. Similar problem is outlined in the post below
how does thread.interrupt() sets the flag?
the following code change should fix the problem:
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
shutdown();
}
}
2) Also because of ThreadConfig::taskExecutor executorPool.setWaitForTasksToCompleteOnShutdown(true) Spring will call executor.shutdown instead of executor.shutdownNow. According to javadoc ExecutorService.shutdown
Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted.
So I would recommend to set
executorPool.setWaitForTasksToCompleteOnShutdown(false);
Other things to improve in this code: although DataMigration is annotated as a component the instances of this class are creared not by Spring. You should try using factory method similar to ThreadConfig::taskExecutor in order to make Spring initiate instances of DataMigration for example to inject other bean into DataMigration instances.
In order to shutdown executor when running jar file on linux environment you can for example add actuator module and enable shutdown endpoint:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
in application.properties:
endpoints.shutdown.enabled=true
It will enable JMX shutdown endpoint and you can call shutdown on it.
If you want current job cycle of the task to be finished you should set
executorPool.setWaitForTasksToCompleteOnShutdown(true);
In order to connect to your jvm process on linux env remotely you have to specify an RMI Registry port.
Here is a detailed article:
How to access Spring-boot JMX remotely
If you just need to connect to JMX from local env you can run jsoncole or command-line tools : Calling JMX MBean method from a shell script
Here is an example uf using one of these tools - jmxterm
$>run -d org.springframework.boot: -b org.springframework.boot:name=shutdownEndpoint,type=Endpoint shutdown
#calling operation shutdown of mbean org.springframework.boot:name=shutdownEndpoint,type=Endpoint with params []
#operation returns:
{
message = Shutting down, bye...;
}

NoClassDefFoundError in Osgi environment

I am working with osgi on apache karaf and I am trying to use kafka and debezium to run into an osgi environment.
kafka and debezium were not osgi ready (karaf will not consider them as bundles), so I did osgified them using eclipse "Plug-in project". The jars that I osgified them are the following : debezium-embedded, debezium-core, kafka connect-api, kafka connect-runtime.
At the begining I get alot of "Class not found exception" when I try to run debezium..
In order to resolve this problem, I changed the manifest of the two bundles. I added an import package to the caller and an export package to the called bundle. Using this I can solve the classNotFound issue.
After solving all the classNotfound issues, I get NoClassDefFoundError
NoClassDefFoundError means that the class loader could not find the .class when it tries to load them ... But I did import all the packages and export them as well.
Any thoughts how to deal with NoClassDefFoundError in an osgi environement
[EDIT Added code]
This is the class Monitor :
public class Monitor {
private Consumer<SourceRecord> consumer = new Consumer<SourceRecord>() {
public void accept(SourceRecord t) {
System.out.println("Change Detected !");
}
};
public void connect() {
System.out.println("Engine Starting");
Configuration config = Configuration.create()
/* begin engine properties */
.with("connector.class", "io.debezium.connector.mysql.MySqlConnector")
.with("offset.storage", "org.apache.kafka.connect.storage.FileOffsetBackingStore")
.with("offset.storage.file.filename", "d:/pathTooffset.dat")
.with("offset.flush.interval.ms", 60000)
/* begin connector properties */
.with("name", "my-sql-connector").with("database.hostname", "localhost").with("database.port", 3306)
.with("database.user", "root").with("database.password", "apassword").with("server.id", 10692)
.with("database.server.name", "localhost")
.with("database.history", "io.debezium.relational.history.FileDatabaseHistory")
.with("database.history.file.filename", "d:/pathTOdbhistory.dat")
.build();
try {
// Create the engine with this configuration ...
EmbeddedEngine engine = EmbeddedEngine.create().using(config).notifying(consumer).build();
Executor executor = Executors.newFixedThreadPool(1);
executor.execute(() -> {
engine.run();
});
} catch (Exception e) {
e.printStackTrace();
}
}
And my activator :
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
Monitor monitor = new Monitor();
monitor.connect();
}
public void stop(BundleContext context) throws Exception {
}}
The problem must be inside EmbeddedEngine. The error could not initialize class means that some static initialization of the class did not work. See this related question noclassdeffounderror-could-not-initialize-class-error.
I propose to run karaf in debug mode and debug through the initialization of this class.

What could cause a class implementing "ApplicationListener<ContextRefreshedEvent>" not to be notified of a "ContextRefreshedEvent"

I have a Spring application listener implementing ApplicationListener<ContextRefreshedEvent> as follows:
#Profile({ Profiles.DEFAULT, Profiles.CLOUD, Profiles.TEST, Profiles.DEV })
#Component
public class BootstrapLoaderListener implements ApplicationListener<ContextRefreshedEvent>, ResourceLoaderAware, Ordered {
private static final Logger log = Logger.getLogger(BootstrapLoaderListener.class);
#Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
#Autowired
private DayToTimeSlotRepository dayToTimeSlotRepository;
#Autowired
private LanguageRepository languageRepository;
private ResourceLoader resourceLoader;
#Override
#Transactional
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
initApplication();
}
private void initApplication() {
if (dayToTimeSlotRepository.count() == 0) {
initDayToTimeSlots();
}
if (languageRepository.count() == 0) {
initLanguages();
}
}
private void initDayToTimeSlots() {
for (Day day : Day.values()) {
for (TimeSlot timeSlot : TimeSlot.values()) {
DayToTimeSlot dayToTimeSlot = new DayToTimeSlot();
dayToTimeSlot.setDay(day);
dayToTimeSlot.setTimeSlot(timeSlot);
dayToTimeSlot.setDisabled(isDayToTimeSlotDisabled(timeSlot, day));
dayToTimeSlotRepository.save(dayToTimeSlot);
}
}
}
...
I rely on this listener class to insert reference data that is not updated nor deleted and I have a number of Spring integration tests that use this class, one of which fails because the listener is not notified (initDayToTimeSlots is not invoked).
I am trying to pinpoint where the problem comes from by debugging the tests and I noticed that when I run the problematic test class on its own, the tests contained in the class pass (indicating that the listener is notified) but when I run all of my application test classes together, the listener is not notified causing the test to fail (indicating that some other test changes/dirties the context).
Here is the problematic test class:
#ActiveProfiles({ Profiles.TEST })
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
public class RegularDayToTimeSlotsTest {
private static int NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK = 25;
#Before
public void setup() {
//org.hsqldb.util.DatabaseManagerSwing.main(new String[] { "--url", "jdbc:hsqldb:mem:bignibou", "--noexit" });
}
#Autowired
private AdvertisementService advertisementService;
#Test
public void shouldNotContainSaturdayNorSunday() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("day").excludes(Day.SATURDAY, Day.SUNDAY);
assertThat(regularDayToTimeSlots).onProperty("day").contains(Day.MONDAY, Day.THUESDAY);
}
#Test
public void shouldNotContainEveningNorNighttime() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("timeSlot").excludes(TimeSlot.EVENING, TimeSlot.NIGHTTIME);
assertThat(regularDayToTimeSlots).onProperty("timeSlot").contains(TimeSlot.MORNING, TimeSlot.LUNCHTIME);
}
#Test
public void shouldContainCorrectNumberOfDayToTimeSlots() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).hasSize(NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK);
}
}
I am puzzled to see that both the prepareRefresh() and finishRefresh() methods within AbstractApplicationContext.refresh method are indeed called but that my listener is not notified...
Has anyone got any clue?
P.S. I know I could use #DirtiesContext in order to get a fresh context and I also know it would be preferable not to rely on an application listener for my tests but I am very anxious to understand what is going wrong here. Hence this post.
edit 1: When I debug the problematic test class in isolation, I notice that the event source is of type GenericApplicationContext and as explained above the test passes OK because the listener is notified. However when all test classes are run together, the event source is, oddly enough, of type GenericWebApplicationContext and no listener is found here in SimpleApplicationEventMulticaster:
#Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
#Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
edit 2: my comments in edit 1 make me asks myself what is responsible for determining the uniqueness of context configuration...
For instance, I have only two test classes with the following context configuration:
#ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
I guess they both will use the same cached context, won't they? Now can a third class use the same cached context even though it does not have exactly the same context configuration?
Why does my test get a GenericWebApplicationContext above?
my comments in edit 1 make me asks myself what is responsible for
determining the uniqueness of context configuration...
The elements that make up the context cache key are described in the Context caching section of the "Testing" chapter in the reference manual.
For instance, I have only two test classes with the following context
configuration:
#ContextConfiguration(classes = {
FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
I guess they both will use the same cached context, won't they?
If they declare only those two configuration classes in that exact order, then yes.
Now can a third class use the same cached context even though it does not
have exactly the same context configuration?
No.
Why does my test get a GenericWebApplicationContext above?
A GenericWebApplicationContext is only loaded if your test class (or one of its superclasses) is annotated with #WebAppConfiguration.
If you are experiencing behavior that contradicts this, then you have discovered a bug in which case we would appreciate it if you could produce a scaled down test project in the issue repository and create a corresponding JIRA issue against the "Spring Framework" and its "Test" component.
Thanks,
Sam (author of the Spring TestContext Framework)

Inject HttpService in an OSGi bundle in JBoss 7

I have a JBoss 7.1.2 application server up and running and now I wanted to deploy a OSGi bundle in it which registers a servlet. (kind of Hello World, but via a servlet)
Probably it is possible to archive this via a WAB, but as in OSGi, I thought it should also work in a simple, non wab bundle.
I created a bundle with an Activator as follows:
snip..
public void start(BundleContext bundleContext) throws Exception {
ServiceReference<?> httpServiceReference = bundleContext.getServiceReference(HttpService.class.getName());
System.out.println("ref: " + httpServiceReference);
HttpService httpService = (HttpService) context.getService(httpServiceReference);
System.out.println(httpService.getClass().getName());
try {
httpService.registerServlet("testservlet", new MyServlet() , null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
After deploying and starting the bundle, the httpServiceReference is null.
I think this is strange, because when I look at the felix web console, there actually is HtttpService available. (from pax-web)
Does anyone know why my reference could be null here?
Thanks!
I think you are making the classical OSGi mistake. In the start(BundleContext context) method you are obtaining the reference to HttpService assuming its already started. The OSGi container starts bundles in some order. If your application bundle starts before the bundle that registers HttpService you will get a null reference. I suspect that's what is going on. You might be better off using ServiceTracker instead.
public void start(BundleContext bundleContext) throws Exception {
ServiceTracker httpServiceTracker = new ServiceTracker(bundleContext, HttpService.class, new ServiceTrackerCustomizer() {
#Override
public Object addingService(ServiceReference srf) {
HttpService httpService = bundleContext.getService(srf);
try {
httpService.registerServlet("testservlet", new MyServlet() , null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void modifiedService(ServiceReference arg0, Object arg1) {
}
#Override
public void removedService(ServiceReference arg0, Object arg1) {
}
});
httpServiceTracker.open();
}

ClassCastException when using embedded glassfish for unit tests

I'm running some unit tests on some EJBS via maven and an embedded glassfish container. One of my tests works, but all subsequent attempts to test a different EJB result in the same error:
java.lang.ClassCastException: $Proxy81 cannot be cast to
Followed by whatever bean I'm attempting to test. I'm confident my setup is good since, as I say, one of my beans can be tested properly.
Examples of workiing code:
#Stateful
public class LayoutManagerBean implements LayoutManager {
private final Log LOG = LogFactory.getLog(LayoutManagerBean.class);
public List<Menu> getMenus(User currentUser) {
...
}
}
#Local
public interface LayoutManager {
public List<Menu> getMenus(User user);
}
And the test:
public class LayoutManagerTest {
private static EJBContainer ejbContainer;
private static Context ctx;
#BeforeClass
public static void setUp() {
ejbContainer = EJBContainer.createEJBContainer();
ctx = ejbContainer.getContext();
}
#AfterClass
public static void tearDown() {
ejbContainer.close();
}
#Test
public void getMenus() {
LayoutManager manager = null;
try {
manager = (LayoutManager) ctx.lookup("java:global/classes/LayoutManagerBean!uk.co.monkeypower.openchurch.core.layout.beans.LayoutManager");
} catch (NamingException e) {
System.out.println("Failed to lookup the gosh darned bean!");
}
assertNotNull(manager);
//Menu[] menus = manager.getMenus();
//assertTrue(menus.length > 1);
}
}
And an example of a failure:
#Singleton
public class OpenChurchPortalContext implements PortalContext {
private Set<PortletMode> portletModes = Collections.emptySet();
private Set<WindowState> windowStates = Collections.emptySet();
private Properties portalProperties = new Properties();
public OpenChurchPortalContext() {
portletModes.add(PortletMode.VIEW);
portletModes.add(PortletMode.HELP);
portletModes.add(PortletMode.EDIT);
portletModes.add(new PortletMode("ABOUT"));
windowStates.add(WindowState.MAXIMIZED);
windowStates.add(WindowState.MINIMIZED);
windowStates.add(WindowState.NORMAL);
}
...
}
And the test:
public class OpenChurchPortalContextTest {
private static EJBContainer ejbContainer;
private static Context ctx;
#BeforeClass
public static void setUp() {
ejbContainer = EJBContainer.createEJBContainer();
ctx = ejbContainer.getContext();
}
#AfterClass
public static void tearDown() {
ejbContainer.close();
}
#Test
public void test() {
OpenChurchPortalContext context = null;
try {
context = (OpenChurchPortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext");
} catch (NamingException e) {
System.out.println("Failed to find the bean in the emebedded jobber");
}
assertNotNull(context);
Set<PortletMode> modes = (Set<PortletMode>) context.getSupportedPortletModes();
assertTrue(modes.size() > 1);
Set<WindowState> states = (Set<WindowState>) context.getSupportedWindowStates();
assertTrue(states.size() > 1);
}
}
Any ideas as to why this may not be working?
You often get this problem if you are proxying a class, not an interface. Assuming that it's this line which is failing:
context = (OpenChurchPortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext");
OpenChurchPortalContext is a class, but it is being wrapped by a proxy class to implement the EJB specific functionality. This proxy class isn't a subclass of OpenChurchPortalContext, so you're getting a ClassCastException.
You aren't getting this with the first example, because the LayoutManager is an interface.
LayoutManager manager = null; // INTERFACE, so it works
try {
manager = (LayoutManager) ctx.lookup("java:global/classes/LayoutManagerBean!uk.co.monkeypower.openchurch.core.layout.beans.LayoutManager");
} catch (NamingException e) {
System.out.println("Failed to lookup the gosh darned bean!");
}
First, you can test to see if this is really your problem, change context to be a PortalContext not OpenChurchPortalContext:
PortalContext context = null;
try {
context = (PortalContext) ctx.lookup("java:global/classes/OpenChurchPortalContext");
} catch (NamingException e) {
System.out.println("Failed to find the bean in the emebedded jobber");
}
If your problem really is the Proxy, then the above code should work. If this is the case, you have two potential solutions:
When you do the ctx.lookup, always use an interface. This can be a bit of a pain, because you need to define an interface specifically for each EJB.
You may be able to configure your EJB container to proxy the classes instead of just the interfaces, similar to proxyTargetClass for Spring AOP. You'll need to check with the documentation for your container for that.
Your singleton EJB has a default local business interface by means of implementing PortalContext interface. The test client should know it only by its business interface, and the actual bean class (OpenChurchPortalContext) should not be referenced directly by the client. So the fix is to look it up by its business interface PortalContext.

Resources