/* * Copyright (c) OSGi Alliance (2013). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package osgi.jdbc.managed.support; import java.util.Hashtable; import java.util.Map; import java.util.Properties; import javax.sql.XADataSource; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.jdbc.DataSourceFactory; import osgi.jdbc.managed.api.ConnectionPoolProvider; import osgi.jdbc.managed.api.DatabaseMigrator; import aQute.bnd.annotation.component.Activate; import aQute.bnd.annotation.component.Component; import aQute.bnd.annotation.component.Deactivate; import aQute.bnd.annotation.component.Reference; import aQute.bnd.annotation.metatype.Meta; import aQute.lib.converter.Converter; /** * This component configures an XA Data Source from a Data Source Factory. It * uses DS's integration with Config Admin to get all the properties. * <p> * We create an XA DataSource since this can be used to create non-transactional * connections. */ @Component(designateFactory = XADataSourceFactory.Config.class) public class XADataSourceFactory { private DataSourceFactory dsf; private XADataSource ds; /** * The configuration interface. Specifies the */ @Meta.OCD(description = "Creates an XA Data Source") interface Config { @Meta.AD(description = "The jdbc url, e.g. `hdbc:h2:mem:`", required = true) String url(); @Meta.AD(description = "The user id (can often also encoded in the URL)", required = false) String user(); @Meta.AD(description = "The password (can often also encoded in the URL)", required = false) String _password(); @Meta.AD(description = "An optional name for this datasource", required = false) String name(); @Meta.AD(description = "Optional filter for selecting a target Data Source Factory", required = false) String dataSourceFactory_target(); } private Config config; private ServiceRegistration<?> registration; private DatabaseMigrator migrator; private ConnectionPoolProvider poolProvider; /** * Awfully simple. Just use the Data Source Factory to create a Data Source. * We delegate all the XA Data Source calls t this Data Source. * * @param properties the DS properties (also from Config admin) * @throws Exception */ @Activate void activate(BundleContext context, Map<String, Object> properties) throws Exception { config = Converter.cnv(Config.class, properties); assert config.url() != null; Properties props = new Properties(); props.put(DataSourceFactory.JDBC_URL, config.url()); if (config.user() != null && config._password() != null) { props.setProperty(DataSourceFactory.JDBC_USER, config.user()); props.setProperty(DataSourceFactory.JDBC_PASSWORD, config._password()); } ds = dsf.createXADataSource(props); if ( migrator != null) migrator.migrate(config.name(), ds); if ( poolProvider != null) ds = poolProvider.pool(ds, properties); registration = context.registerService(XADataSource.class.getName(), ds, new Hashtable<String, Object>( properties)); } @Deactivate void deactivate() { registration.unregister(); } /** * Reference to the Data Source Factory created by the Database driver. The * method is public API because the name is used as a configuration * parameter to select specific Data Source Factory services. * * @param dsf the Data Source factory from the db provider. */ @Reference public void setDataSourceFactory(DataSourceFactory dsf) { this.dsf = dsf; } /** * Reference to a migrator. This method name is public API because it is * used in the configuration for the migrator.target property that sets its * target filter. A migrator can migrate a database to a new version. * * @param migrator */ @Reference(target = "("+DatabaseMigrator.MIGRATOR+"="+DatabaseMigrator.DUMMY+")") public void setMigrator(DatabaseMigrator migrator) { this.migrator = migrator; } /** * Link to a pool provider. This method name is public because it is used in * the target filter. * * @param cpp */ @Reference(target = "("+ConnectionPoolProvider.POOL+"="+ConnectionPoolProvider.DUMMY+")") public void setConnectionPoolProvider(ConnectionPoolProvider cpp) { this.poolProvider = cpp; } }