Package org.apache.jetspeed.components.rdbms.ojb

Source Code of org.apache.jetspeed.components.rdbms.ojb.ConnectionRepositoryEntry

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.jetspeed.components.rdbms.ojb;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ojb.broker.PBKey;
import org.apache.ojb.broker.accesslayer.ConnectionFactoryDBCPImpl;
import org.apache.ojb.broker.accesslayer.ConnectionFactoryManagedImpl;
import org.apache.ojb.broker.accesslayer.LookupException;
import org.apache.ojb.broker.metadata.ConnectionPoolDescriptor;
import org.apache.ojb.broker.metadata.ConnectionRepository;
import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
import org.apache.ojb.broker.metadata.JdbcMetadataUtils;
import org.apache.ojb.broker.metadata.MetadataManager;
import org.apache.ojb.broker.util.ClassHelper;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;

/**
* A JavaBean that configures an entry in OJB's ConnectionRepository
* according to its properties. If a JCD alias is not specified, it defaults
* to the bean's name in the Spring configuration. If the JDBC connection
* descriptor already exists (e.g. because it has been defined in OJB's
* configuration) the properties are merged into the existing descriptor
* (see note about "platform" below), else the JDBC connection descriptor
* is created.<P>
*
* If a JNDI name is set, the bean automatically configures a JDBC connection
* descriptor with a connection factory of type
* <code>ConnectionFactoryManagedImpl</code>, else it uses
* <code>ConectionFactoryDBCPImpl</code>. This may be overridden my setting
* the connection factory property explicitly.<P>
*
* Properties "driverClassName", "url", "username" and "password" are used
* only if no JNDI name is set, i.e. if the connection factory uses the
* driver to create data sources.<P>
*
* The bean derives the RDBMS platform setting from the configured
* data source or database driver using OJB's <code>JdbcMetadataUtils</code>
* class. At least until OJB 1.0.3, however, this class does not properly
* distinguish the platforms "Oracle" and "Oracle9i"; it always assigns
* "Oracle". In case of "Oracle", this bean therefore opens a connection,
* obtains the version information from the database server and adjusts the
* platform accordingly. This behaviour may be overridden by setting the
* <code>platform</code> property of the bean explicitly. Note that the
* attribute "platform" of an already existing JCD is ignored. An already
* existing JCD stems most likely from a configuration file "repository.xml".
* As the DTD for "repository.xml" ("repository.dtd") defines a default
* value for attribute "platform" ("Hsqldb"), it is in general impossible
* to find out whether the platform attribute of an existing JCD has been set
* explicitly or has simply assumed its default value.     
*
* @author Michael Lipp
* @version $Id$
*/
public class ConnectionRepositoryEntry
    extends BasicDataSource
    implements BeanNameAware, InitializingBean
{
    private static final Log log = LogFactory.getLog(ConnectionRepositoryEntry.class);
   
    // general properties
    private String jcdAlias = null;
    private String platform = null;
    private String connectionFactoryClass = null;
    // properties for obtaining data source from JNDI
    private String jndiName = null;
    // properties for creating independant data source
    private String driverClassName = null;
    private String url = null;
    private String username = null;
    private String password = null;
    private boolean jetspeedEngineScoped = true;

    public ConnectionRepositoryEntry()
    {
        super();
    }
   
    /**
     * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
     */
    public void setBeanName(String beanName)
    {
        // Use the bean's name as fallback if a JCD alias is not set
        // explicitly
        if (jcdAlias == null)
        {
            jcdAlias = beanName;
        }
    }
   
    /**
     * @return Returns the jcdAlias.
     */
    public String getJcdAlias()
    {
        return jcdAlias;
    }
   
    /**
     * @param jcdAlias The jcdAlias to set.
     */
    public void setJcdAlias(String jcdAlias)
    {
        this.jcdAlias = jcdAlias;
    }

    /**
     * @return Returns the jndiName.
     */
    public String getJndiName()
    {
        return jndiName;
    }

    /**
     * @param jndiName The jndiName to set.
     */
    public void setJndiName(String jndiName)
    {
        this.jndiName = jndiName;
    }

    /**
     * @return Returns the driverClassName.
     */
    public String getDriverClassName()
    {
        return driverClassName;       
    }

    /**
     * @param driverClassName The driverClassName to set.
     */
    public void setDriverClassName(String driverClassName)
    {
        super.setDriverClassName(driverClassName);
        this.driverClassName = driverClassName;
    }

    /**
     * @return Returns the password.
     */
    public String getPassword()
    {
        return password;
    }

    /**
     * @param password The password to set.
     */
    public void setPassword(String password)
    {
        super.setPassword(password);
        this.password = password;
    }

    /**
     * @return Returns the url.
     */
    public String getUrl()
    {
        return url;
    }

    /**
     * @param url The url to set.
     */
    public void setUrl(String url)
    {
        super.setUrl(url);
        this.url = url;
    }

    /**
     * @return Returns the username.
     */
    public String getUsername()
    {
        return username;
    }

    /**
     * @param username The username to set.
     */
    public void setUsername(String username)
    {
        super.setUsername(username);
        this.username = username;
    }
   
    /**
     * @return Returns the platform.
     */
    public String getPlatform()
    {
        return platform;
    }

    /**
     * Set the platform attribute of the JCD. Setting this property overrides
     * the value derived from the data source or database driver.
     * @param platform The platform to set.
     */
    public void setPlatform(String platform)
    {       
        this.platform = platform;
    }

    /**
     * @see setJetspeedEngineScoped
     * @return Returns if Jetspeed engine's ENC is used for JNDI lookups.
     */
    public boolean isJetspeedEngineScoped()
    {
        return jetspeedEngineScoped;
    }

    /**
     * Sets the attribute "<code>org.apache.jetspeed.engineScoped</code>"
     * of the JDBC connection descriptor to "<code>true</code>" or
     * "<code>false</code>". If set, JNDI lookups of the connection will
     * be done using the environment naming context (ENC) of the Jetspeed
     * engine.
     * @param jetspeedEngineScoped whether to use Jetspeed engine's ENC.
     */
    public void setJetspeedEngineScoped(boolean jetspeedEngineScoped)
    {
        this.jetspeedEngineScoped = jetspeedEngineScoped;
    }

    public void afterPropertiesSet () throws Exception
    {
        // Try to find JCD
        ConnectionRepository cr = MetadataManager.getInstance().connectionRepository();
        JdbcConnectionDescriptor jcd = cr.getDescriptor(new PBKey(jcdAlias));
        if (jcd == null)
        {
            jcd = new JdbcConnectionDescriptor();
            jcd.setJcdAlias(jcdAlias);
            cr.addDescriptor(jcd);
        }
        if (platform != null && platform.length() == 0)
        {
            platform = null;
        }
        DataSource ds = null;
        JdbcMetadataUtils jdbcMetadataUtils = new JdbcMetadataUtils ();
        if (jndiName != null)
        {
            // using "preconfigured" data source
            if (connectionFactoryClass == null)
            {
                connectionFactoryClass = ConnectionFactoryManagedImpl.class.getName ();
            }
            Context initialContext = new InitialContext();
            ds = (DataSource) initialContext.lookup(jndiName);
            jcd.setDatasourceName(jndiName);
        }
        else
        {
            // have to get data source ourselves
            if (connectionFactoryClass == null)
            {
                connectionFactoryClass = ConnectionFactoryDBCPImpl.class.getName ();
            }
            jcd.setDriver(driverClassName);
            Map conData = jdbcMetadataUtils.parseConnectionUrl(url);
            jcd.setDbms(platform);
            jcd.setProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_PROTOCOL));
            jcd.setSubProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_SUBPROTOCOL));
            jcd.setDbAlias((String)conData.get(JdbcMetadataUtils.PROPERTY_DBALIAS));
            jcd.setUserName(username);
            jcd.setPassWord(password);
            // Wrapping the connection factory in a DataSource introduces a bit
            // of redundancy (url is parsed again and platform determined again).
            // But although JdbcMetadataUtils exposes the methods used in
            // fillJCDFromDataSource as public (and these do not require a DataSource)
            // the method itself does more than is made available by the exposed methods.
            // ds = new MinimalDataSource (jcd);
            ds = this;            
        }
        ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor();
        if (cpd == null)
        {
            cpd = new ConnectionPoolDescriptor();
            jcd.setConnectionPoolDescriptor(cpd);
        }
        Class conFacCls = ClassHelper.getClass(connectionFactoryClass);
        cpd.setConnectionFactory(conFacCls);

        jdbcMetadataUtils.fillJCDFromDataSource(jcd, ds, null, null);
       
        if (platform == null && JdbcMetadataUtils.PLATFORM_ORACLE.equals(jcd.getDbms())) {
            // Postprocess to find Oracle version.
            updateOraclePlatform (jcd, ds);
        }
        // if platform has explicitly been set, the value takes precedence
        if (platform != null) {
            if (!platform.equals(jcd.getDbms())) {
                log.warn ("Automatically derived RDBMS platform \"" + jcd.getDbms()
                          + "\" differs from explicitly set platform \"" + platform + "\"");
            }
            jcd.setDbms(platform);
        } else {
            platform = jcd.getDbms();
        }
       
        // special attributes
        jcd.addAttribute("org.apache.jetspeed.engineScoped",
                         Boolean.toString(jetspeedEngineScoped));
    }

    /**
     * @param jcd
     * @throws LookupException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * throws SQLException
     */
    private void updateOraclePlatform(JdbcConnectionDescriptor jcd, DataSource ds)
      throws LookupException, IllegalAccessException, InstantiationException, SQLException
    {
        Connection con = null;
        try
        {
            con = ds.getConnection();
            DatabaseMetaData metaData = con.getMetaData();
            int rdbmsVersion = 0;
            try
            {
                // getDatabaseMajorVersion exists since 1.4, so it may
                // not be defined for the driver used.
                rdbmsVersion = metaData.getDatabaseMajorVersion();
            } catch (Throwable t) {
                String dbVersion = metaData.getDatabaseProductVersion();
                String relKey = "Release";
                String major = dbVersion;
                int startPos = dbVersion.indexOf(relKey);
                if (startPos < 0)
                {
                    log.warn ("Cannot determine Oracle version, no \"Release\" in procuct version: \"" + dbVersion + "\"");
                    return;
                }
                startPos += relKey.length();
                int dotPos = dbVersion.indexOf('.', startPos);
                if (dotPos > 0) {
                    major = dbVersion.substring(startPos, dotPos).trim();
                }
                try
                {
                    rdbmsVersion = Integer.parseInt(major);
                }
                catch (NumberFormatException e)
                {
                    log.warn ("Cannot determine Oracle version, product version \"" + dbVersion + "\" not layed out as \"... Release N.M.....\"");
                    return;
                }
                if (log.isDebugEnabled())
                {
                    log.debug ("Extracted Oracle major version " + rdbmsVersion + " from product version \"" + dbVersion + "\"");
                }
            }
            if (rdbmsVersion >= 9) {
                jcd.setDbms(JdbcMetadataUtils.PLATFORM_ORACLE9I);
            }
        }
        finally
        {
            if (con != null) {
                con.close ();
            }
        }
    }

    /**
     * a minimal DataSource implementation that satisfies the requirements
     * of JdbcMetadataUtil.
     */
    private class MinimalDataSource implements DataSource
    {
        private JdbcConnectionDescriptor jcd = null;
       
        /**
         * Create a new instance using the given JCD.
         */
        public MinimalDataSource (JdbcConnectionDescriptor jcd)
        {
            this.jcd = jcd;
        }
       
        /* (non-Javadoc)
         * @see javax.sql.DataSource#getConnection()
         */
        public Connection getConnection() throws SQLException {
            // Use JDBC DriverManager as we may not rely on JCD to be sufficiently
            // initialized to use any of the ConnectionFactories.
            try {
                // loads the driver - NB call to newInstance() added to force initialisation
                ClassHelper.getClass(jcd.getDriver(), true);
                String url = jcd.getProtocol() + ":" + jcd.getSubProtocol() + ":" + jcd.getDbAlias();
                if (jcd.getUserName() == null)
                {
                    return DriverManager.getConnection(url);
                }
                else
                {
                    return DriverManager.getConnection(url, jcd.getUserName(), jcd.getPassWord());
                }
            }
            catch (ClassNotFoundException e)
            {
                throw (IllegalStateException)
                    (new IllegalStateException (e.getMessage ())).initCause (e);
            }
        }
       
        /**
         * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String)
         */
        public Connection getConnection(String username, String password)
                throws SQLException {
            return getConnection ();
        }

        /**
         * @see javax.sql.DataSource#getLoginTimeout()
         */
        public int getLoginTimeout() throws SQLException
        {
            return 0;
        }

        /**
         * @see javax.sql.DataSource#getLogWriter()
         */
        public PrintWriter getLogWriter() throws SQLException {
            return null;
        }

        /**
         * @see javax.sql.DataSource#setLoginTimeout(int)
         */
        public void setLoginTimeout(int seconds) throws SQLException {
        }

        /**
         * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter)
         */
        public void setLogWriter(PrintWriter out) throws SQLException {
        }
    }

}
TOP

Related Classes of org.apache.jetspeed.components.rdbms.ojb.ConnectionRepositoryEntry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.