How to use an OSGI bundle within a camel route? - java

I have problems using a OSGI-Service in a camel route. Read tutorial-osgi-camel-part1
but didn't get it to work.
The setup:
bundle 1 defines a Service interface (separate bundle for interface because there can be several implementations of it)
bundle 2 implements this interface
bundle 3 should use bundle 2 that provides interface from bundle 1
In bundle 2 (the implementation) are the two xml files, one with
<osgi:service ref="invokeService">
<osgi:interfaces>
<value>invoker.Invoker</value>
</osgi:interfaces>
</osgi:service>
and the other with
<bean id="invokeService" class="invokerImpl.InvokerImpl">
</bean>
Bundle 3 has a xml file with
<osgi:reference id="invokeService" interface="invoker.Invoker"/>
in it.
Bundle 3 and the CamelContext is started with
#Override
public void start(BundleContext bundleContext) throws Exception {
OsgiDefaultCamelContext camelContext = new OsgiDefaultCamelContext(bundleContext);
camelContext.addRoutes(new ExampleRoute());
camelContext.start();
}
In my route I want to use the Service (from bundle 2) with
.to("bean:invokeService")
Exception I get:
19:14:39.953 TRACE o.a.camel.core.osgi.OsgiClassResolver:42 Resolve class invokeService
19:14:39.969 TRACE o.a.camel.core.osgi.OsgiClassResolver:84 Cannot load class: invokeService using classloader: CamleOSGIExample_1.0.0.qualifier [254]. This exception be ignored.
java.lang.ClassNotFoundException: invokeService
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:513) ~[na:na]
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429) ~[na:na]
(...)
and
org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: invokeService
at org.apache.camel.component.bean.RegistryBean.getBean(RegistryBean.java:68) ~[camel-core-2.10.3.jar:2.10.3]
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:83) ~[camel-core-2.10.3.jar:2.10.3]
I'm using Equinox.

Also discussed here and with the solution:
http://camel.465427.n5.nabble.com/Problems-using-a-osgi-bundle-in-a-camel-route-tp5728064.html

Related

Flyway ClassNotFoundException: JavaUtilLogCreator

I'm using Flyway 5.2.4 and OSGI Bundle Activator. I want to migrate database on bundle Start() method.
Here's my ActivatorClass:
import org.flywaydb.core.Flyway;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Activator implements BundleActivator {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private ServiceRegistration serviceRegistration;
public void start(BundleContext bundleContext) {
log.info("Starting...");
serviceRegistration = bundleContext.registerService(IConnector.class.getName(), new Connector(), null);
log.info("Started.");
//FlyWay Section
Flyway flyway = Flyway.configure().dataSource("jdbc:postgresql://localhost:5432/", "postgres", "12345").load();
flyway.migrate();
}
public void stop(BundleContext bundleContext) {
log.info("Stopping...");
serviceRegistration.unregister();
log.info("Stopped.");
}
}
As you can see, I'm using slf4j as my Logger. Maybe that's why I get this errors in my StackTrace after app deploying:
java.lang.Exception: Could not start bundle mvn:internship/db-connector/1.0.0 in feature(s) feature-1.0.0: Activator start error in bundle db-connector [2343].
at org.apache.karaf.features.internal.FeaturesServiceImpl.startBundle(FeaturesServiceImpl.java:519)[20:org.apache.karaf.features.core:3.0.8]
at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(FeaturesServiceImpl.java:474)[20:org.apache.karaf.features.core:3.0.8]
at org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(FeaturesServiceImpl.java:415)[20:org.apache.karaf.features.core:3.0.8]
at Proxy683d032e_ad2c_4b9a_98f7_baca7b5564f1.installFeature(Unknown Source)[:]
at Proxyfff1bf4b_671e_4ff6_bb97_e0dabf9f20e8.installFeature(Unknown Source)[:]
at org.apache.karaf.kar.internal.KarServiceImpl.installFeatures(KarServiceImpl.java:282)[89:org.apache.karaf.kar.core:3.0.8]
at org.apache.karaf.kar.internal.KarServiceImpl.install(KarServiceImpl.java:111)[89:org.apache.karaf.kar.core:3.0.8]
at org.apache.karaf.kar.internal.KarServiceImpl.install(KarServiceImpl.java:93)[89:org.apache.karaf.kar.core:3.0.8]
at Proxy40d8d25a_37b2_4855_a381_fbb78daa68ce.install(Unknown Source)[:]
at Proxy068a2f57_120b_4ee8_b953_7c8262bae9a2.install(Unknown Source)[:]
at org.apache.karaf.deployer.kar.KarArtifactInstaller.update(KarArtifactInstaller.java:62)[91:org.apache.karaf.deployer.kar:3.0.8]
at Proxy3c143b4c_a2ef_49d0_870b_21a9b5f74704.update(Unknown Source)[:]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.update(DirectoryWatcher.java:1101)[7:org.apache.felix.fileinstall:3.5.2]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.update(DirectoryWatcher.java:898)[7:org.apache.felix.fileinstall:3.5.2]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:478)[7:org.apache.felix.fileinstall:3.5.2]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:355)[7:org.apache.felix.fileinstall:3.5.2]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:307)[7:org.apache.felix.fileinstall:3.5.2]
Caused by: org.osgi.framework.BundleException: Activator start error in bundle db-connector [2343].
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2196)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2064)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:942)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.karaf.features.internal.FeaturesServiceImpl.startBundle(FeaturesServiceImpl.java:516)[20:org.apache.karaf.features.core:3.0.8]
... 16 more
Caused by: java.lang.ExceptionInInitializerError
at org.flywaydb.core.internal.util.FeatureDetector.isSlf4jAvailable(FeatureDetector.java:96)
at org.flywaydb.core.internal.logging.LogCreatorFactory.getLogCreator(LogCreatorFactory.java:39)
at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:78)
at org.flywaydb.core.internal.util.FeatureDetector.<clinit>(FeatureDetector.java:25)
at org.flywaydb.core.internal.logging.LogCreatorFactory.getLogCreator(LogCreatorFactory.java:35)
at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:78)
at org.flywaydb.core.Flyway.<clinit>(Flyway.java:86)
at internship.connectors.postgresConnector.Activator.start(Activator.java:18)
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:645)
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2146)
... 20 more
Caused by: org.flywaydb.core.api.FlywayException: Unable to instantiate class org.flywaydb.core.internal.logging.javautil.JavaUtilLogCreator : org.flywaydb.core.internal.logging.javautil.JavaUtilLogCreator
at org.flywaydb.core.internal.util.ClassUtils.instantiate(ClassUtils.java:63)[2348:org.flywaydb.core:5.2.4]
at org.flywaydb.core.internal.logging.LogCreatorFactory.getLogCreator(LogCreatorFactory.java:46)[2348:org.flywaydb.core:5.2.4]
at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:78)[2348:org.flywaydb.core:5.2.4]
at org.flywaydb.core.internal.util.ClassUtils.<clinit>(ClassUtils.java:39)[2348:org.flywaydb.core:5.2.4]
... 30 more
Caused by: java.lang.ClassNotFoundException: org.flywaydb.core.internal.logging.javautil.JavaUtilLogCreator
at java.net.URLClassLoader.findClass(Unknown Source)[:1.8.0_212]
at java.lang.ClassLoader.loadClass(Unknown Source)[:1.8.0_212]
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)[:1.8.0_212]
at java.lang.ClassLoader.loadClass(Unknown Source)[:1.8.0_212]
at java.lang.Class.forName0(Native Method)[:1.8.0_212]
at java.lang.Class.forName(Unknown Source)[:1.8.0_212]
at org.flywaydb.core.internal.util.ClassUtils.instantiate(ClassUtils.java:61)[2348:org.flywaydb.core:5.2.4]
... 33 more
So, I just have no idea what's wrong here, I've used simpliest example from official Flyway's site and get this errors.
I've already try to delete my own Logger. I thought it can let FlyWay to use it's logger, but everything goes the same way (same errors).
Could you help me?
P.S. Looks like this pull request somehow related to my problem.
Indeed it seems Flyway might have issues in OSGi. Maybe you can provide them an issue and your example.
Another issue with your example is that you try to access the DataSource via a url. This does not work in OSGi. The reason is that this way flyway has to have direct access to the database driver classes. This does not work in OSGi.
In OSGi the way to access a Database is with a DataSourceFactory which the database driver creates as a service. From this factory you can create a DataSource.
As not all database drivers offer this service there is pax-jdbc which provides factories for all common databases. It also allows to create a DataSource including pooling from a OSGi config.
Your approach of migrating on bundle start is a very bad idea. The methods in the activator must return quickly and a databse migration might take a while. Of course you want to make sure the migration takes place before any bundle in the system accesses the database. Fortunately there is a way to hook into the DataSource creation to do things like a migration.
See the liquibase tutorial which also shows a database migration. It uses the PreHook offered by pax-jdbc which makes sure your migration code is run before the DataSource is given to any other bundle.
I managed to avoid this error by setting a custom LogFactory before entering flyway's migration code. The basic idea is presented in this sample commit

Is it possible to outhouse ShutdownStrategy for CamelContext into a central OSGi bundle?

I am trying to outhouse central beans of my OSGi bundles into a central bundle, which provides them as a service. This works fine with the ErrorHanlders and Processors, but not with the ShutdownStrategy and RedeliveryPolicy. The Error Message I receive is
org.osgi.service.blueprint.container.ComponentDefinitionException: A class org.apache.camel.processor.RedeliveryPolicy was found in the interfaces list, but class proxying is not allowed by default. The ext:proxy-method='classes' attribute needs to be added to this service reference.
I could try to follow the instrutction and add the ext:proxy-method, but first I want to understand the clue here. Maybe it's not a good idea to centralize strategies and policies?
[EDIT] The mistake here was to use the class in the service instead of an interface. So interface="org.apache.camel.spi.ShutdownStrategy" should be the correct Interface here (for the ShutdownStrategy). The bundle with my camel route references this service so:
<reference
id="shutdownStrategy"
interface="org.apache.camel.spi.ShutdownStrategy"
component-name="shutdownStrategy" />
But now I get the following error:
java.lang.IllegalArgumentException: CamelContext must be specified
[EDIT] I want to confine this question to the ShutdownStrategy, because the RedeliveryPolicy works fine when I referenc it in the ErrorHandlers inside my central bundle.
So is it possible to outhouse the ShutdownStrategy, too? Maybe not, because it needs a CamelContext.
When using Spring XML you then just define a spring bean which implements the org.apache.camel.spi.ShutdownStrategy and Camel will look it up at startup and use it instead of its default.
I found the answer in the Camel documentation
You can implement your own strategy to control the shutdown by implementing the org.apache.camel.spi.ShutdownStrategy and the set it on the CamelContext using the setShutdownStrategy method.
When using Spring XML you then just define a spring bean which implements the org.apache.camel.spi.ShutdownStrategy and Camel will look it up at startup and use it instead of its default.
So if you have your own implementation of the ShutdownStrategy you can use it as a bean.
<bean id="shutdownStrategy"
class="org.apache.camel.spi.ShutdownStrategy">
</bean>

JCA Connector Classloading

in my Scenario, i try to use JCA Adapters to connect to an external storage - just to try this feature of J2EE.
I use JBoss EAP 7 and its packed implementation ironjacamar.
i deploy an adapter.rar, which contains an adapter.jar (this contains the Connection and ConnectionFactory Interfaces and all implementations) and META-INF/ironjacamar.xml.
I then deploy a app.war file, containing a Bean with an annotated field:
#RequestScoped
public class Bean {
...
#Resource(lookup = "java:/eis/StorageConnectionFactory")
private StorageConnectionFactory connectionFactory;
}
The war also contains the adapter.jar as library - as it needs to know of all the classes at runtime (NoClassDefFound etc.)
To my amazement, the Connector itself seems to work - as is get the Exception:
java.lang.IllegalArgumentException: Can not set conn.StorageConnectionFactoryImpl field Bean.connectionFactory to conn.HsmConnectionFactoryImp
and on ommitting the interfaces even:
#Resource(lookup = "java:/eis/StorageConnectionFactory")
private StorageConnectionFactoryImpl connectionFactory;
still
java.lang.IllegalArgumentException: Can not set conn.StorageConnectionFactoryImpl field Bean.connectionFactory to conn.HsmConnectionFactoryImp
I see that the Problem is, that the adapter.rar does nto share the same classloader as the app.war and both contain the corresponding classes, leading to a sort of ClassCastException - how do i solve this issue correctly?
It seems you haven't configure resource adapter properly.
See the below guide, it will help you to configure:
https://access.redhat.com/documentation/en/red-hat-jboss-enterprise-application-platform/version-7.0/configuration-guide/#configuring_jca_subsystem

AspectJExpressionPointcut uses wrong classLoader

I have a Java EE application consisting of multiple OSGi bundles running within Apache Felix container. One of these bundles is responsible for loading Spring application context.
I'm using Spring AOP in my application and the following error arised in my bundle:
java.lang.IllegalArgumentException: warning no match for this type name: com.somepackage.SomeClass [Xlint:invalidAbsoluteTypeName]
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:206)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:192)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:169)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:208)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:262)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:294)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:330)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1573)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
The cause of this problem is that class(com.somepackage.SomeClass) used in pointcat of my aspect was loaded by bundle ClassLoader but AspectJExpressionPointcut passes default ClassLoader to buildPointcutExpression() method:
private void checkReadyToMatch() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
which knows nothing about this class (com.somepackage.SomeClass).
The problem was solved by changing ClassLoader in thread initializing Spring Application Context:
Thread.currentThread().setContextClassLoader(bundleClassLoader);
So method ClassUtils.getDefaultClassLoader() returns bundleClassLoader which can load class mentioned in pointcut.

GridException Failed to add no-op logger for Log4j on GridGain startup

I'm having trouble to get started with gridgain, i'm using the xml configuration file that come with gridgain examples example-cache.xml (Is there a simpler configuration file?).
When I start gridgain as follows I got a GridException:
public static void main(String[] args) throws GridException, URISyntaxException {
URL url = GridgainCache.class.getClassLoader().getResource("gridgain.xml");
String filename = url.toURI().toString();
System.out.println("Reading gridgain conf from: "+filename);
Grid g = GridGain.start(filename);
...
}
Here is full stack trace:
Exception in thread "main" class org.gridgain.grid.GridException: Failed to add no-op logger for Log4j.
For more information see:
Troubleshooting: http://bit.ly/GridGain-Troubleshooting
Documentation Center: http://bit.ly/GridGain-Documentation
at org.gridgain.grid.util.GridUtils.addLog4jNoOpLogger(GridUtils.java:7709)
at org.gridgain.grid.kernal.GridGainEx.start(GridGainEx.java:714)
at org.gridgain.grid.kernal.GridGainEx.start(GridGainEx.java:659)
at org.gridgain.grid.kernal.GridGainEx.start(GridGainEx.java:522)
at org.gridgain.grid.kernal.GridGainEx.start(GridGainEx.java:492)
at org.gridgain.grid.GridGain.start(GridGain.java:314)
at com.examples.gridgain.GridgainCache.main(GridgainCache.java:102)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gridgain.grid.util.GridUtils.addLog4jNoOpLogger(GridUtils.java:7706)
... 6 more
Do I need to configure log4j? i'm using slf4j.
GridGain checks if there are Log4j classes available in classpath and tries to add Log4j logger automatically, which in your case leads to the error because of Log4j version mismatch.
Since you cannot switch to the Log4j v1.2.17 supported by GridGain, you should configure another logger manually. I would use SLF4j bridge matching the version of Log4j you already have (note you will need to add gridgain-slf4j dependency):
<property name="gridLogger">
<bean class="org.gridgain.grid.logger.slf4j.GridSlf4jLogger"/>
</property>
Another option is to use Java logging (no additional dependencies needed)
<property name="gridLogger">
<bean class="org.gridgain.grid.logger.java.GridJavaLogger"/>
</property>

Categories