View Javadoc

1   /*
2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    * 1. Redistributions of source code must retain the above copyright notice,
8    *    this list of conditions and the following disclaimer.
9    * 2. Redistributions in binary form must reproduce the above copyright notice,
10   *    this list of conditions and the following disclaimer in the documentation
11   *    and/or other materials provided with the distribution.
12   * 3. The end-user documentation included with the redistribution, if any, must
13   *    include the following acknowledgment:
14   *
15   *       "This product includes software developed by Gargoyle Software Inc.
16   *        (http://www.GargoyleSoftware.com/)."
17   *
18   *    Alternately, this acknowledgment may appear in the software itself, if
19   *    and wherever such third-party acknowledgments normally appear.
20   * 4. The name "Gargoyle Software" must not be used to endorse or promote
21   *    products derived from this software without prior written permission.
22   *    For written permission, please contact info@GargoyleSoftware.com.
23   * 5. Products derived from this software may not be called "GSBase", nor may
24   *    "GSBase" appear in their name, without prior written permission of
25   *    Gargoyle Software Inc.
26   *
27   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30   * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   */
38  package com.gargoylesoftware.base.resource.jdbc;
39  
40  import com.gargoylesoftware.base.resource.ManagedResource;
41  import com.gargoylesoftware.base.resource.ResourceException;
42  import com.gargoylesoftware.base.resource.ResourceFactory;
43  import com.gargoylesoftware.base.resource.ResourceManager;
44  import java.sql.Connection;
45  import java.sql.DriverManager;
46  import java.sql.SQLException;
47  
48  /***
49   *  A ResourceFactory for JDBC connections
50   *
51   * @version  $Revision: 1.5 $
52   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
53   */
54  public class JDBCResourceFactory extends ResourceFactory {
55  
56      private final String databaseName_;
57      private final String userName_;
58      private final String password_;
59  
60  
61      /***
62       *  Create the factory. The database driver must have been registered prior
63       *  to creating an instance of this class. This constructor will always try
64       *  to allocate one connection right away to ensure that the database
65       *  information was entered correctly.
66       *
67       * @param  databaseName The name of the database
68       * @param  userName The user id that we will use to connect to the database
69       * @param  password The password for the specified user
70       * @exception  SQLException If an error occurs
71       */
72      public JDBCResourceFactory(
73              final String databaseName,
74              final String userName,
75              final String password )
76          throws
77              SQLException {
78          this( databaseName, userName, password, true );
79      }
80  
81  
82      /***
83       *  Create the factory. The database driver must have been registered prior
84       *  to creating an instance of this class.
85       *
86       * @param  databaseName The name of the database
87       * @param  userName The user id that we will use to connect to the database
88       * @param  password The password for the specified user
89       * @param  verifyThatConnectionCanBeOpened If true than one connection will
90       *      be immediately allocated and then freed from the specified database
91       * @exception  SQLException If an error occurs
92       */
93      public JDBCResourceFactory(
94              final String databaseName,
95              final String userName,
96              final String password,
97              final boolean verifyThatConnectionCanBeOpened )
98          throws
99              SQLException {
100 
101         if( databaseName == null ) {
102             throw new NullPointerException( "databaseName" );
103         }
104         if( userName == null ) {
105             throw new NullPointerException( "userName" );
106         }
107         if( password == null ) {
108             throw new NullPointerException( "password" );
109         }
110 
111         databaseName_ = databaseName;
112         userName_ = userName;
113         password_ = password;
114 
115         if( verifyThatConnectionCanBeOpened == true ) {
116             ensureDatabaseCanBeOpened();
117         }
118     }
119 
120 
121     /***
122      *  Reinitialize the resource to a known state. This is required for
123      *  resource pooling as all resources being returned from a pool must have
124      *  been initialized to a known state.
125      *
126      * @param  resource the resource to reinitialize
127      * @return  true if the resource was successfully reinitialized
128      */
129     public boolean reinitializeResourceIfPossible(
130             ManagedResource resource ) {
131         final ConnectionWrapper wrapper = ( ConnectionWrapper )resource;
132 
133         boolean result = false;
134 
135         try {
136             if( wrapper.isClosed() == false ) {
137                 result = true;
138 
139                 wrapper.commit();
140                 wrapper.setAutoCommit( true );
141                 wrapper.closeAnyOpenStatements();
142                 wrapper.closeAnyOpenMetaDatas();
143             }
144         }
145         catch( final SQLException e ) {
146             // If any errors occurred then we can't return it to the pool
147             result = false;
148         }
149 
150         return result;
151     }
152 
153 
154     /***
155      *  Allocate a resource for the specified store
156      *
157      * @param  resourceManager The resource manager that owns this factory
158      * @return  The new resource
159      * @exception  Exception If an error occurs
160      */
161     protected ManagedResource getResourceImpl(
162             final ResourceManager resourceManager )
163         throws
164             Exception {
165 
166         return new ConnectionWrapper(
167                 DriverManager.getConnection( databaseName_, userName_, password_ ) );
168     }
169 
170 
171     /***
172      *  Release the specified resource. It must have been allocated by the
173      *  specified store
174      *
175      * @param  resource The resource that we are releasing
176      * @param  resourceManager The manager that is controlling this factory
177      * @exception  Exception If an error occurs
178      */
179     protected void releaseResourceImpl(
180             final ResourceManager resourceManager,
181             final ManagedResource resource )
182         throws
183             Exception {
184 
185         final ConnectionWrapper wrapper = ( ConnectionWrapper )resource;
186         if( wrapper.isClosed() == false ) {
187             wrapper.close();
188         }
189     }
190 
191 
192     /***
193      *  Allocate a real database connection from the DriverManager
194      *
195      * @param  databaseName The name of the database
196      * @param  userName The user id that we will use to connect to the database
197      * @param  password The password for the specified user
198      * @return  A new connection
199      * @exception  SQLException If an error occurs
200      */
201     protected final Connection allocateRealConnection(
202             final String databaseName,
203             final String userName,
204             final String password )
205         throws
206             SQLException {
207 
208         return DriverManager.getConnection( databaseName, userName, password );
209     }
210 
211 
212     /***
213      *  Free a real database connection
214      *
215      * @param  connection The connection to release
216      * @exception  SQLException If an error occurs
217      */
218     protected final void freeRealConnection(
219             final Connection connection )
220         throws
221             SQLException {
222 
223         connection.close();
224     }
225 
226 
227     private void ensureDatabaseCanBeOpened()
228         throws SQLException {
229 
230         final ResourceManager resourceManager = new ResourceManager( "EnsureDatabaseCanBeOpened" );
231         try {
232             final ConnectionWrapper connection = ( ConnectionWrapper )getResource( resourceManager );
233             releaseResource( resourceManager, connection );
234         }
235         catch( final ResourceException e ) {
236             final Throwable enclosedException = e.getEnclosedException();
237             if( enclosedException instanceof SQLException ) {
238                 throw ( SQLException )enclosedException;
239             }
240 
241             throw e;
242         }
243     }
244 }
245