/* * #%L * Wisdom-Framework * %% * Copyright (C) 2013 - 2014 Wisdom Framework * %% * 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. * #L% */ package org.wisdom.database.jdbc.impl; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.wisdom.api.configuration.Configuration; import org.wisdom.database.jdbc.service.DataSources; import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.logging.Logger; /** * An implementation of data source delegating call an a wrapped data source. This implementation act as a 'weak * reference' as the wrapped data source may not be available. */ public class WrappedDataSource implements DataSource { private Configuration configuration; private final String name; private DataSource wrapped; private ServiceRegistration<DataSource> registration; public WrappedDataSource(String name, Configuration conf) { this.name = name; this.configuration = conf; } public String getName() { return name; } public synchronized void set(DataSource source) { this.wrapped = source; } public synchronized void unset() { this.wrapped = null; } public synchronized boolean isAvailable() { return wrapped != null; } /** * <p>Attempts to establish a connection with the data source that * this <code>DataSource</code> object represents. * * @return a connection to the data source * @throws java.sql.SQLException if a database access error occurs */ @Override public Connection getConnection() throws SQLException { return wrapped.getConnection(); } /** * <p>Attempts to establish a connection with the data source that * this <code>DataSource</code> object represents. * * @param username the database user on whose behalf the connection is * being made * @param password the user's password * @return a connection to the data source * @throws java.sql.SQLException if a database access error occurs * @since 1.4 */ @Override public Connection getConnection(String username, String password) throws SQLException { return wrapped.getConnection(username, password); } /** * <p>Retrieves the log writer for this <code>DataSource</code> * object. * <p/> * <p>The log writer is a character output stream to which all logging * and tracing messages for this data source will be * printed. This includes messages printed by the methods of this * object, messages printed by methods of other objects manufactured * by this object, and so on. Messages printed to a data source * specific log writer are not printed to the log writer associated * with the <code>java.sql.DriverManager</code> class. When a * <code>DataSource</code> object is * created, the log writer is initially null; in other words, the * default is for logging to be disabled. * * @return the log writer for this data source or null if * logging is disabled * @throws java.sql.SQLException if a database access error occurs * @see #setLogWriter * @since 1.4 */ @Override public PrintWriter getLogWriter() throws SQLException { return wrapped.getLogWriter(); } /** * <p>Sets the log writer for this <code>DataSource</code> * object to the given <code>java.io.PrintWriter</code> object. * <p/> * <p>The log writer is a character output stream to which all logging * and tracing messages for this data source will be * printed. This includes messages printed by the methods of this * object, messages printed by methods of other objects manufactured * by this object, and so on. Messages printed to a data source- * specific log writer are not printed to the log writer associated * with the <code>java.sql.DriverManager</code> class. When a * <code>DataSource</code> object is created the log writer is * initially null; in other words, the default is for logging to be * disabled. * * @param out the new log writer; to disable logging, set to null * @throws java.sql.SQLException if a database access error occurs * @see #getLogWriter * @since 1.4 */ @Override public void setLogWriter(PrintWriter out) throws SQLException { wrapped.setLogWriter(out); } /** * <p>Sets the maximum time in seconds that this data source will wait * while attempting to connect to a database. A value of zero * specifies that the timeout is the default system timeout * if there is one; otherwise, it specifies that there is no timeout. * When a <code>DataSource</code> object is created, the login timeout is * initially zero. * * @param seconds the data source login time limit * @throws java.sql.SQLException if a database access error occurs. * @see #getLoginTimeout * @since 1.4 */ @Override public void setLoginTimeout(int seconds) throws SQLException { wrapped.setLoginTimeout(seconds); } /** * Gets the maximum time in seconds that this data source can wait * while attempting to connect to a database. A value of zero * means that the timeout is the default system timeout * if there is one; otherwise, it means that there is no timeout. * When a <code>DataSource</code> object is created, the login timeout is * initially zero. * * @return the data source login time limit * @throws java.sql.SQLException if a database access error occurs. * @see #setLoginTimeout * @since 1.4 */ @Override public int getLoginTimeout() throws SQLException { return wrapped.getLoginTimeout(); } /** * Return the parent Logger of all the Loggers used by this data source. This * should be the Logger farthest from the root Logger that is * still an ancestor of all of the Loggers used by this data source. Configuring * this Logger will affect all of the log messages generated by the data source. * In the worst case, this may be the root Logger. * * @return the parent Logger for this data source * @throws java.sql.SQLFeatureNotSupportedException if the data source does not use <code>java.util.logging</code>. * @since 1.7 */ @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return wrapped.getParentLogger(); } /** * Returns an object that implements the given interface to allow access to * non-standard methods, or standard methods not exposed by the proxy. * <p/> * If the receiver implements the interface then the result is the receiver * or a proxy for the receiver. If the receiver is a wrapper * and the wrapped object implements the interface then the result is the * wrapped object or a proxy for the wrapped object. Otherwise return the * the result of calling <code>unwrap</code> recursively on the wrapped object * or a proxy for that result. If the receiver is not a * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown. * * @param iface A Class defining an interface that the result must implement. * @return an object that implements the interface. May be a proxy for the actual implementing object. * @throws java.sql.SQLException If no object found that implements the interface * @since 1.6 */ public <T> T unwrap(Class<T> iface) throws SQLException { return wrapped.unwrap(iface); } /** * Returns true if this either implements the interface argument or is directly or indirectly a wrapper * for an object that does. Returns false otherwise. If this implements the interface then return true, * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped * object. If this does not implement the interface and is not a wrapper, return false. * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method * returns true then calling <code>unwrap</code> with the same argument should succeed. * * @param iface a Class defining an interface. * @return true if this implements the interface or directly or indirectly wraps an object that does. * @throws java.sql.SQLException if an error occurs while determining whether this is a wrapper * for an object with the given interface. * @since 1.6 */ public boolean isWrapperFor(Class<?> iface) throws SQLException { return wrapped.isWrapperFor(iface); } public Configuration getConfiguration() { return configuration; } public String getRequiredDriver() { return configuration.get("driver"); } public void register(BundleContext context) { if (registration != null) { return; } Dictionary<String, String> props = new Hashtable<>(); Configuration serviceProperties = configuration.getConfiguration("properties"); if(serviceProperties!=null){ Properties properties = serviceProperties.asProperties(); for(Enumeration<Object> keys = properties.keys(); keys.hasMoreElements(); /* NO-OP */){ String serviceProp = (String) keys.nextElement(); props.put(serviceProp, serviceProperties.getOrDie(serviceProp)); } } // // "name" property value from application.conf will silently override the value from service properties. // props.put(DataSources.DATASOURCE_NAME_PROPERTY, name); registration = context.registerService(DataSource.class, this, props); } public void unregister() { if (registration != null) { registration.unregister(); registration = null; } } public DataSource getWrapped() { return wrapped; } public WrappedDataSource updateConfiguration(Configuration configuration) { this.configuration = configuration; return this; } }