You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@sling.apache.org by JCR <jc...@proxymit.net> on 2021/03/01 09:08:58 UTC

Re: Sling/Felix JDBC Connection Pool problem

Yes, the pool is called by a class in an OSGI bundle with the dependency 
shown in my previous email.

But indeed, we have strong reasons that we are talking about a 
classloader issue here. In the meanwhile, I tested the JDBC "vanilla 
approach":

     Class.forName("org.mariadb.jdbc.Driver");
     Connection con = 
DriverManager.getConnection("jdbc:mariadb://localhost:3306/dbdb", 
"dbuser1", "pwd");

and a direct DataSource approach:

             MariaDbDataSource ds = new MariaDbDataSource();
             ds.setUser("dbuser1");
             ds.setPassword("pwd");
             ds.setServerName("localhost");
             ds.setPortNumber(3306);
             ds.setDatabaseName("dbdb");
             con = ds.getConnection();

The first version returns with a runtime error that the Driver-class is 
not found. The second version behaves similarly

     java.lang.NoClassDefFoundError: javax/sql/DataSource

Now, javax.sql is even a standard part of Felix. If I add this 
dependency to pom:

<dependency>
     <groupId>javax.sql</groupId>
     <artifactId>jdbc-stdext</artifactId>
     <version>2.0</version>
</dependency>

  ... Eclipse marks an error saying "Missing artifact 
javax.sql:jdbc-stdext:jar:1.0". That's strange because the jar is in 
/home/juerg/.m2/repository/javax/sql and most probably also in core 
Felix, otherwise it wouldn't be possible the establish a pool.

And now coming to the point: the "vanilla approach" works perfectly in 
the Servlet/JSP environment! I don't know in what context that part of 
Sling exactly runs, but the Driver class is seemingly found and DB 
interaction works.
But from an architectural perspective, a JSP is obviously not the place 
where database code should be placed...

Question is, how can access to the driver be achieved from an OSGi bundle?

Best,
Juerg


On 26.02.21 18:13, Eric Norman wrote:
> I'm not using JDBC datasources personally, but can you clarify in what
> context your client code is running?
>
> In general the @Reference annotations (both the older felix.scr ones and
> the newer standardardized annotations from OSGi R6 specification) are only
> going to work when they are within a declarative service component and that
> client class is accessed as an osgi service.
>
> If the client code is running in some other context or lookup of the client
> class happens some other way, then you would likely need a different way to
> get the reference to the DataSource component.
>
> For example, sling models can use the @Inject annotation for getting a
> reference to an osgi service, or you can get the DataSource service
> reference from a ServiceTracker or a direct service reference lookup from
> some BundleContext.
>
> Regards,
> Eric
>
> On Fri, Feb 26, 2021 at 7:04 AM JCR <jc...@proxymit.net> wrote:
>
>> Adding a detail: The @Reference annotation is deprecated.
>>
>> ****************************
>>
>> For creating a JDBC connection pool (to mariadb) in Sling 11, I followed
>> the instructions given at
>> https://sling.apache.org/documentation/bundles/datasource-providers.html
>> . However, I get a runtime exception on the datasource without further
>> details.
>>
>> As documented on that webpage, I declared the following in the consuming
>> class:
>>
>> import org.apache.felix.scr.annotations.Reference;
>>
>> public class Database {
>>
>>       @Reference(target =
>> "(&(objectclass=javax.sql.DataSource)(datasource.name=dbdb))")
>>       DataSource dataSource;
>>
>>       public String test() {
>>
>>           try {
>>
>>               Connection con = dataSource.getConnection();
>>
>>               ... Some SQL instructions...
>>
>>       }
>>
>> The config of the datasource was done via the Felix console and looks like:
>>
>>       in JNDI DataSource:
>>
>>           Datasource name(*): dbdb
>>           JNDI name(*): dbdb
>>
>>       in Apache Sling Connection Pooled DataSource:
>>
>>           Datasource name(*): dbdb
>>           JDBC driver class: org.mariadb.jdbc.Driver
>>           JDBC connection URI:
>> jdbc:mysql://localhost:3306/someDB?useUnicode=yes&characterEncoding=UTF-8
>>           Username: xyz
>>           .... many more
>>
>> The POM:
>>       <dependency>
>>               <groupId>org.apache.felix</groupId>
>> <artifactId>org.apache.felix.scr.annotations</artifactId>
>>               <version>1.12.0</version>
>>           </dependency>
>>
>>
>> Now, the datasource, at the moment of calling test() is null. I have
>> absolutely no hint what the problem is. The config? The annotation? What
>> is obvious, however, is that the /@Reference /as suggested on the
>> bundles page, is deprecated... What would be the most current approach?
>>
>> Thanks,
>> -Juerg
>>
>>
>>
>>

Re: Sling/Felix JDBC Connection Pool problem

Posted by Robert Munteanu <ro...@apache.org>.
Hi,

On Mon, 2021-03-01 at 10:08 +0100, JCR wrote:
>      Class.forName("org.mariadb.jdbc.Driver");
>      Connection con = 
> DriverManager.getConnection("jdbc:mariadb://localhost:3306/dbdb", 
> "dbuser1", "pwd");

In addition to what others have said, please avoid using Class.forName
in OSGi environments

  https://blog.hargrave.io/2007/09/classforname-caches-defined-class-in.html

Thanks,
Robert


Re: Sling/Felix JDBC Connection Pool problem

Posted by Julian Sedding <js...@gmail.com>.
Hello Juerg

Have you read the documentation at
https://sling.apache.org/documentation/bundles/datasource-providers.html#driver-loading?
I could imagine that you are struggling with one of the issues
described there.

Basically, IIUC, the Sling DataSource Provider bundle tries to create
a DataSource based on a configuration and register it as a service.
You seem to have the configuration in place, but don't get a
DataSource injected. Assuming the @Reference annotated field is indeed
in a valid OSGi declarative service component, one possible reason is
that Sling's DataSource Provider fails to load the MariaDB driver
class, another is that there is an error initializing it.

You could check in the web console if your DataSource is registered as
a service. You could also check the logs to see if there are any
problems logged by the DataSource Provider. Based on the docs, you
could see if the MariaDB bundle contains the file
META-INF/services/java.sql.Driver.

Hope this helps a little. I don't work with DataSources normally, so YMMV.

Regards
Julian

On Mon, Mar 1, 2021 at 10:09 AM JCR <jc...@proxymit.net> wrote:
>
> Yes, the pool is called by a class in an OSGI bundle with the dependency
> shown in my previous email.
>
> But indeed, we have strong reasons that we are talking about a
> classloader issue here. In the meanwhile, I tested the JDBC "vanilla
> approach":
>
>      Class.forName("org.mariadb.jdbc.Driver");
>      Connection con =
> DriverManager.getConnection("jdbc:mariadb://localhost:3306/dbdb",
> "dbuser1", "pwd");
>
> and a direct DataSource approach:
>
>              MariaDbDataSource ds = new MariaDbDataSource();
>              ds.setUser("dbuser1");
>              ds.setPassword("pwd");
>              ds.setServerName("localhost");
>              ds.setPortNumber(3306);
>              ds.setDatabaseName("dbdb");
>              con = ds.getConnection();
>
> The first version returns with a runtime error that the Driver-class is
> not found. The second version behaves similarly
>
>      java.lang.NoClassDefFoundError: javax/sql/DataSource
>
> Now, javax.sql is even a standard part of Felix. If I add this
> dependency to pom:
>
> <dependency>
>      <groupId>javax.sql</groupId>
>      <artifactId>jdbc-stdext</artifactId>
>      <version>2.0</version>
> </dependency>
>
>   ... Eclipse marks an error saying "Missing artifact
> javax.sql:jdbc-stdext:jar:1.0". That's strange because the jar is in
> /home/juerg/.m2/repository/javax/sql and most probably also in core
> Felix, otherwise it wouldn't be possible the establish a pool.
>
> And now coming to the point: the "vanilla approach" works perfectly in
> the Servlet/JSP environment! I don't know in what context that part of
> Sling exactly runs, but the Driver class is seemingly found and DB
> interaction works.
> But from an architectural perspective, a JSP is obviously not the place
> where database code should be placed...
>
> Question is, how can access to the driver be achieved from an OSGi bundle?
>
> Best,
> Juerg
>
>
> On 26.02.21 18:13, Eric Norman wrote:
> > I'm not using JDBC datasources personally, but can you clarify in what
> > context your client code is running?
> >
> > In general the @Reference annotations (both the older felix.scr ones and
> > the newer standardardized annotations from OSGi R6 specification) are only
> > going to work when they are within a declarative service component and that
> > client class is accessed as an osgi service.
> >
> > If the client code is running in some other context or lookup of the client
> > class happens some other way, then you would likely need a different way to
> > get the reference to the DataSource component.
> >
> > For example, sling models can use the @Inject annotation for getting a
> > reference to an osgi service, or you can get the DataSource service
> > reference from a ServiceTracker or a direct service reference lookup from
> > some BundleContext.
> >
> > Regards,
> > Eric
> >
> > On Fri, Feb 26, 2021 at 7:04 AM JCR <jc...@proxymit.net> wrote:
> >
> >> Adding a detail: The @Reference annotation is deprecated.
> >>
> >> ****************************
> >>
> >> For creating a JDBC connection pool (to mariadb) in Sling 11, I followed
> >> the instructions given at
> >> https://sling.apache.org/documentation/bundles/datasource-providers.html
> >> . However, I get a runtime exception on the datasource without further
> >> details.
> >>
> >> As documented on that webpage, I declared the following in the consuming
> >> class:
> >>
> >> import org.apache.felix.scr.annotations.Reference;
> >>
> >> public class Database {
> >>
> >>       @Reference(target =
> >> "(&(objectclass=javax.sql.DataSource)(datasource.name=dbdb))")
> >>       DataSource dataSource;
> >>
> >>       public String test() {
> >>
> >>           try {
> >>
> >>               Connection con = dataSource.getConnection();
> >>
> >>               ... Some SQL instructions...
> >>
> >>       }
> >>
> >> The config of the datasource was done via the Felix console and looks like:
> >>
> >>       in JNDI DataSource:
> >>
> >>           Datasource name(*): dbdb
> >>           JNDI name(*): dbdb
> >>
> >>       in Apache Sling Connection Pooled DataSource:
> >>
> >>           Datasource name(*): dbdb
> >>           JDBC driver class: org.mariadb.jdbc.Driver
> >>           JDBC connection URI:
> >> jdbc:mysql://localhost:3306/someDB?useUnicode=yes&characterEncoding=UTF-8
> >>           Username: xyz
> >>           .... many more
> >>
> >> The POM:
> >>       <dependency>
> >>               <groupId>org.apache.felix</groupId>
> >> <artifactId>org.apache.felix.scr.annotations</artifactId>
> >>               <version>1.12.0</version>
> >>           </dependency>
> >>
> >>
> >> Now, the datasource, at the moment of calling test() is null. I have
> >> absolutely no hint what the problem is. The config? The annotation? What
> >> is obvious, however, is that the /@Reference /as suggested on the
> >> bundles page, is deprecated... What would be the most current approach?
> >>
> >> Thanks,
> >> -Juerg
> >>
> >>
> >>
> >>

Re: Sling/Felix JDBC Connection Pool problem

Posted by Eric Norman <en...@apache.org>.
Hi Juerg,

I'm still not clear if you are trying to reference the DataSource service
from within another OSGi service or from some POJO class.   The description
of the original problem suggests it is not within an OSGi service as a
failure to inject the non-optional @Reference should have caused that OSGi
service to fail to activate.

If this is indeed a POJO class, you may try something like this:

import java.util.Collection;

import javax.sql.DataSource;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DSExamplePojo {
    private Logger logger = LoggerFactory.getLogger(getClass());

    public void doSomething() {
        // get the bundle this class lives in
        Bundle bundle = FrameworkUtil.getBundle(getClass());
        // and the bundle context to lookup a service
        BundleContext bundleContext = bundle.getBundleContext();

        // lookup the service
        DataSource ds = null;
        Collection<ServiceReference<DataSource>> serviceReferences = null;
        try {
            serviceReferences =
bundleContext.getServiceReferences(DataSource.class, "(datasource.name
=dbdb)");
        } catch (InvalidSyntaxException e) {
            logger.error("Failed to get service references", e);
        }
        if (serviceReferences != null && !serviceReferences.isEmpty()) {
            // get the first match
            ServiceReference<DataSource> ref =
serviceReferences.iterator().next();
            try {
                // get the service from the service reference
                ds = bundleContext.getService(ref);
            } finally {
                // cleanup
                bundleContext.ungetService(ref);
            }

            //TODO: use the ds variable to do something here
            logger.info("Found DataSource: {}", ds);
        }
    }

}


Regards,
-Eric

On Mon, Mar 1, 2021 at 1:09 AM JCR <jc...@proxymit.net> wrote:

> Yes, the pool is called by a class in an OSGI bundle with the dependency
> shown in my previous email.
>
> But indeed, we have strong reasons that we are talking about a
> classloader issue here. In the meanwhile, I tested the JDBC "vanilla
> approach":
>
>      Class.forName("org.mariadb.jdbc.Driver");
>      Connection con =
> DriverManager.getConnection("jdbc:mariadb://localhost:3306/dbdb",
> "dbuser1", "pwd");
>
> and a direct DataSource approach:
>
>              MariaDbDataSource ds = new MariaDbDataSource();
>              ds.setUser("dbuser1");
>              ds.setPassword("pwd");
>              ds.setServerName("localhost");
>              ds.setPortNumber(3306);
>              ds.setDatabaseName("dbdb");
>              con = ds.getConnection();
>
> The first version returns with a runtime error that the Driver-class is
> not found. The second version behaves similarly
>
>      java.lang.NoClassDefFoundError: javax/sql/DataSource
>
> Now, javax.sql is even a standard part of Felix. If I add this
> dependency to pom:
>
> <dependency>
>      <groupId>javax.sql</groupId>
>      <artifactId>jdbc-stdext</artifactId>
>      <version>2.0</version>
> </dependency>
>
>   ... Eclipse marks an error saying "Missing artifact
> javax.sql:jdbc-stdext:jar:1.0". That's strange because the jar is in
> /home/juerg/.m2/repository/javax/sql and most probably also in core
> Felix, otherwise it wouldn't be possible the establish a pool.
>
> And now coming to the point: the "vanilla approach" works perfectly in
> the Servlet/JSP environment! I don't know in what context that part of
> Sling exactly runs, but the Driver class is seemingly found and DB
> interaction works.
> But from an architectural perspective, a JSP is obviously not the place
> where database code should be placed...
>
> Question is, how can access to the driver be achieved from an OSGi bundle?
>
> Best,
> Juerg
>
>
> On 26.02.21 18:13, Eric Norman wrote:
> > I'm not using JDBC datasources personally, but can you clarify in what
> > context your client code is running?
> >
> > In general the @Reference annotations (both the older felix.scr ones and
> > the newer standardardized annotations from OSGi R6 specification) are
> only
> > going to work when they are within a declarative service component and
> that
> > client class is accessed as an osgi service.
> >
> > If the client code is running in some other context or lookup of the
> client
> > class happens some other way, then you would likely need a different way
> to
> > get the reference to the DataSource component.
> >
> > For example, sling models can use the @Inject annotation for getting a
> > reference to an osgi service, or you can get the DataSource service
> > reference from a ServiceTracker or a direct service reference lookup from
> > some BundleContext.
> >
> > Regards,
> > Eric
> >
> > On Fri, Feb 26, 2021 at 7:04 AM JCR <jc...@proxymit.net> wrote:
> >
> >> Adding a detail: The @Reference annotation is deprecated.
> >>
> >> ****************************
> >>
> >> For creating a JDBC connection pool (to mariadb) in Sling 11, I followed
> >> the instructions given at
> >>
> https://sling.apache.org/documentation/bundles/datasource-providers.html
> >> . However, I get a runtime exception on the datasource without further
> >> details.
> >>
> >> As documented on that webpage, I declared the following in the consuming
> >> class:
> >>
> >> import org.apache.felix.scr.annotations.Reference;
> >>
> >> public class Database {
> >>
> >>       @Reference(target =
> >> "(&(objectclass=javax.sql.DataSource)(datasource.name=dbdb))")
> >>       DataSource dataSource;
> >>
> >>       public String test() {
> >>
> >>           try {
> >>
> >>               Connection con = dataSource.getConnection();
> >>
> >>               ... Some SQL instructions...
> >>
> >>       }
> >>
> >> The config of the datasource was done via the Felix console and looks
> like:
> >>
> >>       in JNDI DataSource:
> >>
> >>           Datasource name(*): dbdb
> >>           JNDI name(*): dbdb
> >>
> >>       in Apache Sling Connection Pooled DataSource:
> >>
> >>           Datasource name(*): dbdb
> >>           JDBC driver class: org.mariadb.jdbc.Driver
> >>           JDBC connection URI:
> >>
> jdbc:mysql://localhost:3306/someDB?useUnicode=yes&characterEncoding=UTF-8
> >>           Username: xyz
> >>           .... many more
> >>
> >> The POM:
> >>       <dependency>
> >>               <groupId>org.apache.felix</groupId>
> >> <artifactId>org.apache.felix.scr.annotations</artifactId>
> >>               <version>1.12.0</version>
> >>           </dependency>
> >>
> >>
> >> Now, the datasource, at the moment of calling test() is null. I have
> >> absolutely no hint what the problem is. The config? The annotation? What
> >> is obvious, however, is that the /@Reference /as suggested on the
> >> bundles page, is deprecated... What would be the most current approach?
> >>
> >> Thanks,
> >> -Juerg
> >>
> >>
> >>
> >>
>