M4V3N
M4V3N

Reputation: 629

how to pass a datasource to a library?

I am writing a library which retrieves data from a specific data schema. This library holds a Datasource object which can be anything. Right now I have defined the name of the datasource within the library which I would like to avoid.

import javax.sql.DataSource

public class MyLibraryDao.java {
   private static final DS_NAME = "MY_DS_NAME";

   @Resource(name = "default", lookup = DS_NAME , type = DataSource.class)
   protected DataSource dataSource;
}

The DAO class is not directly exposed to the client. There is a service layer inbetween:

import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Model;

@ApplicationScoped
@Model
public class MyLibraryService {

    @Inject
    MyLibraryDao dao;
}

Now, how would I pass the datasource object to the library?

I assume I need to create a constructor in the DAO with takes a DataSource but what about the service? The library will be used in a CDI environment.

Upvotes: 1

Views: 558

Answers (1)

Nikos Paraskevopoulos
Nikos Paraskevopoulos

Reputation: 40296

First things first your library needs a datasource, let's declare the dependency:

public class MyLibraryDao {
   @Inject
   protected DataSource dataSource;
}

Now the rest of the application that is using the library is responsible to provide a datasource to CDI; a simple way is:

// Example; your implementation may vary
public class AppDatasourceProducer {
    private static final DS_NAME = "MY_APP_DS_NAME";

    @Resource(name = "default", lookup = DS_NAME , type = DataSource.class)
    protected DataSource dataSource;

    @Produces
    @ApplicationScoped
    public DataSource getDatasource() {
        return dataSource;
    }
}

What's changed? Now your application is responsible for knowing the datasource name AND providing the datasource itself. The example above can work in JEE environments that honor the @Resource annotation. Using a different implementation for the provider would work in e.g. a desktop environment (standalone application), making your library reusable.

The exact datasource name may be fixed, just like in the example, or read from configuration, e.g. from system properties (like mentioned in a comment); e.g.:

// Example 2, DS name from system properties
@ApplicationScoped
public class AppDatasourceProducer {
    protected DataSource dataSource;

    @PostConstruct
    void init() throws Exception {
        String dsName = System.getProperty("XXXXX");
        InitialContext ic = new InitialContext();
        dataSource = (DataSource) ic.lookup(dsName);
    }

    @Produces
    @ApplicationScoped
    public DataSource getDatasource() {
        return dataSource;
    }
}

Going further:

  1. An application that uses your library may be using several datasources, for whatever reason. You may want to provide a qualifier to specify the datasource to be used by your app.
  2. I used field injection in MyLibraryDao for simplicity. If you change to constructor injection then, at least MyLibraryDao, will be usable in non-CDI environments as well, i.e. if you have obtained a DataSource somehow, you can now do new MyLibraryDao(datasource). Even more reusability.

Upvotes: 2

Related Questions