提交 09406c99 authored 作者: noelgrandin's avatar noelgrandin

Improved OSGi support. H2 now registers itself as a DataSourceFactory service. Fixes issue 365.

上级 61f2493e
...@@ -26,6 +26,7 @@ Change Log ...@@ -26,6 +26,7 @@ Change Log
</ul><li>MVStore: compress is now disabled by default, and can be enabled on request. </ul><li>MVStore: compress is now disabled by default, and can be enabled on request.
</ul><li>Support ALTER TABLE ADD ... AFTER. Patch from Andrew Gaul argaul@gmail.com. Fixes issue 401. </ul><li>Support ALTER TABLE ADD ... AFTER. Patch from Andrew Gaul argaul@gmail.com. Fixes issue 401.
</ul><li>support "SELECT version()". Patch from Andrew Gaul argaul@gmail.com. Fixes issue 406. </ul><li>support "SELECT version()". Patch from Andrew Gaul argaul@gmail.com. Fixes issue 406.
</ul><li>Improved OSGi support. H2 now registers itself as a DataSourceFactory service. Fixes issue 365.
</li></ul> </li></ul>
<h2>Version 1.3.170 (2012-11-30)</h2> <h2>Version 1.3.170 (2012-11-30)</h2>
......
...@@ -66,6 +66,8 @@ Tutorial ...@@ -66,6 +66,8 @@ Tutorial
Date and Time</a><br /> Date and Time</a><br />
<a href="#spring"> <a href="#spring">
Using Spring</a><br /> Using Spring</a><br />
<a href="#osgi">
OSGi</a><br />
<a href="#jmx"> <a href="#jmx">
Java Management Extension (JMX)</a><br /> Java Management Extension (JMX)</a><br />
...@@ -1407,6 +1409,20 @@ The workaround is to add the following XML file to the root of the classpath: ...@@ -1407,6 +1409,20 @@ The workaround is to add the following XML file to the root of the classpath:
&lt;/beans&gt; &lt;/beans&gt;
</pre> </pre>
<h2 id="osgi">OSGi</h2>
<p>
The standard H2 jar can be dropped in as a bundle in an OSGi container. H2 implements the
JDBC Service defined in OSGi Service Platform Release 4 Version 4.2 Enterprise Specification.
The H2 Data Source Factory service is registered with the following properties
OSGI_JDBC_DRIVER_CLASS=org.h2.Driver and OSGI_JDBC_DRIVER_NAME=H2. The OSGI_JDBC_DRIVER_VERSION
property reflects the version of the driver as is.
</p>
<p>
The following standard configuration properties are supported: JDBC_USER, JDBC_PASSWORD, JDBC_DESCRIPTION,
JDBC_DATASOURCE_NAME, JDBC_NETWORK_PROTOCOL, JDBC_URL, JDBC_SERVER_NAME, JDBC_PORT_NUMBER. Any other standard
property will be rejected. Non-standard properties will be passed on to H2 in the connection URL.
</p>
<h2 id="jmx">Java Management Extension (JMX)</h2> <h2 id="jmx">Java Management Extension (JMX)</h2>
<p> <p>
Management over JMX is supported, but not enabled by default. Management over JMX is supported, but not enabled by default.
......
...@@ -11,10 +11,39 @@ Bundle-Name: H2 Database Engine ...@@ -11,10 +11,39 @@ Bundle-Name: H2 Database Engine
Bundle-SymbolicName: org.h2 Bundle-SymbolicName: org.h2
Bundle-Vendor: H2 Group Bundle-Vendor: H2 Group
Bundle-Version: ${version} Bundle-Version: ${version}
DynamicImport-Package: * Bundle-License: http://www.h2database.com/html/license.html
Bundle-Category: jdbc
Import-Package: javax.management,
javax.naming;resolution:=optional,
javax.naming.spi;resolution:=optional,
javax.net,
javax.net.ssl,
javax.servlet;resolution:=optional,
javax.servlet.http;resolution:=optional,
javax.sql,
javax.transaction.xa;resolution:=optional,
org.apache.lucene.analysis;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.analysis.standard;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.document;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.index;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.queryParser;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.search;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.store;version="[3.0.0,3.1.0)";resolution:=optional,
org.apache.lucene.util;version="[3.0.0,3.1.0)";resolution:=optional,
org.h2;version="[${version},1.4.0)",
org.h2.api;version="[${version},1.4.0)",
org.h2.fulltext;version="[${version},1.4.0)",
org.h2.jdbcx;version="[${version},1.4.0)",
org.h2.tools;version="[${version},1.4.0)",
org.h2.util;version="[${version},1.4.0)",
org.osgi.framework;version="1.5",
org.osgi.service.jdbc;version="1.0",
org.slf4j;version="[1.6.0,1.7.0)";resolution:=optional
Export-Package: org.h2;version="${version}", Export-Package: org.h2;version="${version}",
org.h2.api;version="${version}", org.h2.api;version="${version}",
org.h2.constant;version="${version}",
org.h2.fulltext;version="${version}", org.h2.fulltext;version="${version}",
org.h2.jdbc;version="${version}",
org.h2.jdbcx;version="${version}", org.h2.jdbcx;version="${version}",
org.h2.tools;version="${version}", org.h2.tools;version="${version}",
org.h2.util;version="${version}" org.h2.util;version="${version}"
......
/* /*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, Version
* Version 1.0, and under the Eclipse Public License, Version 1.0 * 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html). Initial Developer: H2 Group
* Initial Developer: H2 Group
*/ */
package org.h2.util; package org.h2.util;
import java.util.Properties;
import org.h2.engine.Constants;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import org.osgi.service.jdbc.DataSourceFactory;
/** /**
* The driver activator loads the H2 driver when starting the bundle. * The driver activator loads the H2 driver when starting the bundle. The driver
* The driver is unloaded when stopping the bundle. * is unloaded when stopping the bundle.
*/ */
public class DbDriverActivator implements BundleActivator { public class DbDriverActivator implements BundleActivator {
/** /**
* Start the bundle. This will load and register the database driver. * Start the bundle. This will load the database driver and register the
* DataSourceFactory service.
* *
* @param bundleContext the bundle context * @param bundleContext the bundle context
*/ */
public void start(BundleContext bundleContext) { public void start(BundleContext bundleContext) {
org.h2.Driver.load(); org.h2.Driver driver = org.h2.Driver.load();
Properties properties = new Properties();
properties.put(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, org.h2.Driver.class.getName());
properties.put(DataSourceFactory.OSGI_JDBC_DRIVER_NAME, "H2");
properties.put(DataSourceFactory.OSGI_JDBC_DRIVER_VERSION, Constants.getVersion());
bundleContext.registerService(DataSourceFactory.class.getName(), new OsgiDataSourceFactory(driver), properties);
} }
/** /**
* Stop the bundle. This will deregister the database driver. * Stop the bundle. This will unload the database driver. The
* DataSourceFactory service is implicitly un-registered by the OSGi
* framework.
* *
* @param bundleContext the bundle context * @param bundleContext the bundle context
*/ */
......
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, Version
* 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). Initial Developer: H2 Group
*/
package org.h2.util;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.h2.engine.Constants;
import org.h2.jdbcx.JdbcDataSource;
import org.osgi.service.jdbc.DataSourceFactory;
/**
* This class implements the OSGi DataSourceFactory interface for the H2 JDBC
* driver. The following standard configuration properties are supported:
* {@link #JDBC_USER}, {@link #JDBC_PASSWORD}, {@link #JDBC_DESCRIPTION},
* {@link #JDBC_DATASOURCE_NAME}, {@link #JDBC_NETWORK_PROTOCOL},
* {@link #JDBC_URL}, {@link #JDBC_SERVER_NAME}, {@link #JDBC_PORT_NUMBER}. The
* following standard configuration properties are not supported:
* {@link #JDBC_ROLE_NAME}, {@link #JDBC_DATABASE_NAME},
* {@link #JDBC_INITIAL_POOL_SIZE}, {@link #JDBC_MAX_POOL_SIZE},
* {@link #JDBC_MIN_POOL_SIZE}, {@link #JDBC_MAX_IDLE_TIME},
* {@link #JDBC_MAX_STATEMENTS}, {@link #JDBC_PROPERTY_CYCLE}. Any other
* property will be treated as a H2 specific option. If the {@link #JDBC_URL}
* property is passed to any of the DataSource factories, the following
* properties will be ignored: {@link #JDBC_DATASOURCE_NAME},
* {@link #JDBC_NETWORK_PROTOCOL}, {@link #JDBC_SERVER_NAME},
* {@link #JDBC_PORT_NUMBER}.
*
* @author Per Otterstrom
*/
public class OsgiDataSourceFactory implements DataSourceFactory {
private org.h2.Driver driver;
public OsgiDataSourceFactory(org.h2.Driver driver) {
this.driver = driver;
}
/**
* Creates a basic data source.
*
* @param properties the properties for the data source.
* @throws SQLException if unsupported properties are supplied, or if data
* source can not be created.
* @return a new data source.
*/
public DataSource createDataSource(Properties properties) throws SQLException {
// Make copy of properties
Properties propertiesCopy = new Properties();
if (properties != null) {
propertiesCopy.putAll(properties);
}
// Verify that no unsupported standard options are used
rejectUnsupportedOptions(propertiesCopy);
// Standard pool properties in OSGi not applicable here
rejectPoolingOptions(propertiesCopy);
JdbcDataSource dataSource = new JdbcDataSource();
setupH2DataSource(dataSource, propertiesCopy);
return dataSource;
}
/**
* Creates a pooled data source.
*
* @param properties the properties for the data source.
* @throws SQLException if unsupported properties are supplied, or if data
* source can not be created.
* @return a new data source.
*/
public ConnectionPoolDataSource createConnectionPoolDataSource(Properties properties) throws SQLException {
// Make copy of properties
Properties propertiesCopy = new Properties();
if (properties != null) {
propertiesCopy.putAll(properties);
}
// Verify that no unsupported standard options are used
rejectUnsupportedOptions(propertiesCopy);
// The integrated connection pool is H2 is not configurable
rejectPoolingOptions(propertiesCopy);
JdbcDataSource dataSource = new JdbcDataSource();
setupH2DataSource(dataSource, propertiesCopy);
return dataSource;
}
/**
* Creates a pooled XA data source.
*
* @param properties the properties for the data source.
* @throws SQLException if unsupported properties are supplied, or if data
* source can not be created.
* @return a new data source.
*/
public XADataSource createXADataSource(Properties properties) throws SQLException {
// Make copy of properties
Properties propertiesCopy = new Properties();
if (properties != null) {
propertiesCopy.putAll(properties);
}
// Verify that no unsupported standard options are used
rejectUnsupportedOptions(propertiesCopy);
// The integrated connection pool is H2 is not configurable
rejectPoolingOptions(propertiesCopy);
JdbcDataSource dataSource = new JdbcDataSource();
setupH2DataSource(dataSource, propertiesCopy);
return dataSource;
}
/**
* Returns a driver. The H2 driver does not support any properties.
*
* @param properties must be null or empty list.
* @throws SQLException if any property is supplied.
* @return a driver.
*/
public java.sql.Driver createDriver(Properties properties) throws SQLException {
if (properties != null && !properties.isEmpty()) {
// No properties supported
throw new SQLException();
}
return driver;
}
/**
* Checker method that will throw if any unsupported standard OSGi options
* is present.
*
* @param properties the properties to check
* @throws SQLFeatureNotSupportedException if unsupported properties are
* present
*/
private void rejectUnsupportedOptions(final Properties properties) throws SQLFeatureNotSupportedException {
// Unsupported standard properties in OSGi
if (properties.containsKey(DataSourceFactory.JDBC_ROLE_NAME)) {
throw new SQLFeatureNotSupportedException("The " + DataSourceFactory.JDBC_ROLE_NAME
+ " property is not supported by H2");
}
if (properties.containsKey(DataSourceFactory.JDBC_DATASOURCE_NAME)) {
throw new SQLFeatureNotSupportedException("The " + DataSourceFactory.JDBC_DATASOURCE_NAME
+ " property is not supported by H2");
}
}
/**
* Applies common OSGi properties to a H2 data source. Non standard
* properties will be applied as H2 options.
*
* @param dataSource the data source to configure
* @param properties the properties to apply to the data source
*/
private void setupH2DataSource(final JdbcDataSource dataSource, final Properties properties) {
// Setting user and password
if (properties.containsKey(DataSourceFactory.JDBC_USER)) {
dataSource.setUser((String) properties.remove(DataSourceFactory.JDBC_USER));
}
if (properties.containsKey(DataSourceFactory.JDBC_PASSWORD)) {
dataSource.setPassword((String) properties.remove(DataSourceFactory.JDBC_PASSWORD));
}
// Setting description
if (properties.containsKey(DataSourceFactory.JDBC_DESCRIPTION)) {
dataSource.setDescription((String) properties.remove(DataSourceFactory.JDBC_DESCRIPTION));
}
// Setting URL
StringBuffer connectionUrl = new StringBuffer();
if (properties.containsKey(DataSourceFactory.JDBC_URL)) {
// Use URL if specified
connectionUrl.append(properties.remove(DataSourceFactory.JDBC_URL));
// Remove individual properties
properties.remove(DataSourceFactory.JDBC_NETWORK_PROTOCOL);
properties.remove(DataSourceFactory.JDBC_SERVER_NAME);
properties.remove(DataSourceFactory.JDBC_PORT_NUMBER);
properties.remove(DataSourceFactory.JDBC_DATABASE_NAME);
} else {
// Creating URL from individual properties
connectionUrl.append(Constants.START_URL);
// Set network protocol (tcp/ssl) or DB type (mem/file)
String protocol = "";
if (properties.containsKey(DataSourceFactory.JDBC_NETWORK_PROTOCOL)) {
protocol = (String) properties.remove(DataSourceFactory.JDBC_NETWORK_PROTOCOL);
connectionUrl.append(protocol).append(":");
}
// Host name and/or port
if (properties.containsKey(DataSourceFactory.JDBC_SERVER_NAME)) {
connectionUrl.append("//").append(properties.remove(DataSourceFactory.JDBC_SERVER_NAME));
if (properties.containsKey(DataSourceFactory.JDBC_PORT_NUMBER)) {
connectionUrl.append(":").append(properties.remove(DataSourceFactory.JDBC_PORT_NUMBER));
}
connectionUrl.append("/");
} else if (properties.containsKey(DataSourceFactory.JDBC_PORT_NUMBER)) {
// Assume local host if only port was set
connectionUrl.append("//localhost:").append(properties.remove(DataSourceFactory.JDBC_PORT_NUMBER))
.append("/");
} else if (protocol.equals("tcp") || protocol.equals("ssl")) {
// Assume local host if network protocol is set, but no host or
// port is set
connectionUrl.append("//localhost/");
}
// DB path and name
if (properties.containsKey(DataSourceFactory.JDBC_DATABASE_NAME)) {
connectionUrl.append(properties.remove(DataSourceFactory.JDBC_DATABASE_NAME));
}
}
// Add remaining properties as options
for (Object option : properties.keySet()) {
connectionUrl.append(";").append(option).append("=").append(properties.get(option));
}
if (connectionUrl.length() > Constants.START_URL.length()) {
dataSource.setURL(connectionUrl.toString());
}
}
/**
* Checker method that will throw if any pooling related standard OSGi
* options are present.
*
* @param properties the properties to check
* @throws SQLFeatureNotSupportedException if unsupported properties are
* present
*/
private void rejectPoolingOptions(final Properties properties) throws SQLFeatureNotSupportedException {
if (properties.containsKey(DataSourceFactory.JDBC_INITIAL_POOL_SIZE)
|| properties.containsKey(DataSourceFactory.JDBC_MAX_IDLE_TIME)
|| properties.containsKey(DataSourceFactory.JDBC_MAX_POOL_SIZE)
|| properties.containsKey(DataSourceFactory.JDBC_MAX_STATEMENTS)
|| properties.containsKey(DataSourceFactory.JDBC_MIN_POOL_SIZE)
|| properties.containsKey(DataSourceFactory.JDBC_PROPERTY_CYCLE)) {
throw new SQLFeatureNotSupportedException("Pooling properties are not supported by H2");
}
}
}
...@@ -112,7 +112,8 @@ public class Build extends BuildBase { ...@@ -112,7 +112,8 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/" + getLuceneJar() + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/h2mig_pagestore_addon.jar" + File.pathSeparator + "ext/h2mig_pagestore_addon.jar" +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" + File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" +
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" + File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" + File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" +
File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar"; File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar";
...@@ -155,7 +156,8 @@ public class Build extends BuildBase { ...@@ -155,7 +156,8 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/" + getLuceneJar() + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" + File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar" + File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" +
File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar"; File.pathSeparator + System.getProperty("java.home") + "/../lib/tools.jar";
FileList files; FileList files;
if (clientOnly) { if (clientOnly) {
...@@ -244,8 +246,10 @@ public class Build extends BuildBase { ...@@ -244,8 +246,10 @@ public class Build extends BuildBase {
} }
downloadOrVerify("ext/slf4j-api-1.6.0.jar", "org/slf4j", "slf4j-api", "1.6.0", downloadOrVerify("ext/slf4j-api-1.6.0.jar", "org/slf4j", "slf4j-api", "1.6.0",
"b353147a7d51fcfcd818d8aa6784839783db0915", offline); "b353147a7d51fcfcd818d8aa6784839783db0915", offline);
downloadOrVerify("ext/org.osgi.core-1.2.0.jar", "org/apache/felix", "org.osgi.core", "1.2.0", downloadOrVerify("ext/org.osgi.core-4.2.0.jar", "org/osgi", "org.osgi.core", "4.2.0",
"3006beb1ca6a83449def6127dad3c060148a0209", offline); "66ab449ff3aa5c4adfc82c89025cc983b422eb95", offline);
downloadOrVerify("ext/org.osgi.enterprise-4.2.0.jar", "org/osgi", "org.osgi.enterprise", "4.2.0",
"8634dcb0fc62196e820ed0f1062993c377f74972", offline);
} }
private void downloadOrVerify(String target, String group, String artifact, private void downloadOrVerify(String target, String group, String artifact,
...@@ -506,7 +510,8 @@ public class Build extends BuildBase { ...@@ -506,7 +510,8 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" + File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/" + getLuceneJar() + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar", File.pathSeparator + "ext/org.osgi.core-4.2.0.jar",
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar",
"-subpackages", "org.h2", "-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu"); "-exclude", "org.h2.test.jaqu:org.h2.jaqu");
System.setProperty("h2.interfacesOnly", "false"); System.setProperty("h2.interfacesOnly", "false");
...@@ -516,7 +521,8 @@ public class Build extends BuildBase { ...@@ -516,7 +521,8 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" + File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/servlet-api-2.4.jar" + File.pathSeparator + "ext/servlet-api-2.4.jar" +
File.pathSeparator + "ext/" + getLuceneJar() + File.pathSeparator + "ext/" + getLuceneJar() +
File.pathSeparator + "ext/org.osgi.core-1.2.0.jar", File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar",
"-subpackages", "org.h2", "-subpackages", "org.h2",
"-exclude", "org.h2.test.jaqu:org.h2.jaqu", "-exclude", "org.h2.test.jaqu:org.h2.jaqu",
"-package", "-package",
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论