Coverage details for com.topcoder.document.index.persistence.impl.db.AbstractDBIndexPersistence

LineHitsSource
1 /*
2  * Copyright (C) 2006 TopCoder Inc., All Rights Reserved.
3  */
4 package com.topcoder.document.index.persistence.impl.db;
5  
6 import com.topcoder.db.connectionfactory.ConfigurationException;
7 import com.topcoder.db.connectionfactory.DBConnectionException;
8 import com.topcoder.db.connectionfactory.DBConnectionFactory;
9 import com.topcoder.db.connectionfactory.DBConnectionFactoryImpl;
10 import com.topcoder.db.connectionfactory.UnknownConnectionException;
11 import com.topcoder.document.index.persistence.IndexPersistence;
12 import com.topcoder.document.index.persistence.IndexPersistenceException;
13 import com.topcoder.document.index.persistence.impl.PersistenceConfigurationException;
14 import com.topcoder.document.index.persistence.impl.Utils;
15  
16 import java.lang.reflect.Constructor;
17 import java.sql.Connection;
18 import java.sql.SQLException;
19 import java.util.Arrays;
20  
21  
22 /**
23  * This is an abstraction of a typical data base driven persistence contract. This provides for getting a connection
24  * from the DBConnectionFactory as well as specifying transaction control. This hides nicely the intricacies of
25  * configuration that would be used by all derived classes.
26  * <p/>
27  * <b>Thread safety:</b>This class is no designed to be thread-safe.
28  *
29  * @author AleaActaEst, TCSDEVELOPER
30  * @version 1.0
31  */
32 public abstract class AbstractDBIndexPersistence implements IndexPersistence {
33  
34     /**
35      * This is the {@link com.topcoder.util.config.ConfigManager} lookup key used for reading the connection factory
36      * class name from the ConfigManager.
37      */
38     private static final String CONNECTION_FACTORY_CLASS_NAME_PROPERTY_NAME = "ConnectionFactoryClassName";
39     /**
40      * This is the {@link com.topcoder.util.config.ConfigManager} lookup key used for reading the connection factory
41      * namespace from the ConfigManager.
42      */
43     private static final String CONNECTION_FACTORY_NAMESPACE_PROPERTY_NAME = "ConnectionFactoryNamespace";
44     /**
45      * This is the {@link com.topcoder.util.config.ConfigManager} lookup key used for reading the {@link
46      * #connectionName} from the ConfigManager.
47      */
48     private static final String CONNECTION_NAME_PROPERTY_NAME = "ConnectionName";
49  
50     /**
51      * This field holds the connection factory from which we will obtain a pre-configured connection for our data base
52      * access. This is initialized in one of the constructors. Cannot be <tt>null</tt>.
53      */
54     private final DBConnectionFactory connectionFactory;
55  
56     /**
57      * This field holds a connection name (an alias) that is used to fetch a connection instance from the connection
58      * factory. This is initialized in one of the constructors and once initialized cannot be changed. Can be
59      * <tt>null</tt> or an empty string, upon which it will try to use the default connection.
60      */
61     private final String connectionName;
62  
63     /**
64      * This constructor will populate the connectionFactory and connectionName information from configuration.
65      *
66      * @param namespace The namespace for connection-related properties.
67      *
68      * @throws IllegalArgumentException if namespace param is <tt>null</tt> or an empty (trim'd) String
69      * @throws PersistenceConfigurationException
70      * if there are configuration issues encountered
71      */
72647    protected AbstractDBIndexPersistence(final String namespace) throws PersistenceConfigurationException {
73647        if (namespace == null) {
743            throw new IllegalArgumentException("The parameter named [namespace] was null.");
75         }
76644        if (namespace.trim().length() == 0) {
772            throw new IllegalArgumentException("The parameter named [namespace] was an empty String.");
78         }
79  
80642        final String connectionFactoryClass = Utils.lookupOptionalStringFromConfigManager(namespace,
81             CONNECTION_FACTORY_CLASS_NAME_PROPERTY_NAME);
82642        final String connectionFactoryNamespace = Utils.lookupValidStringFromConfigManager(namespace,
83             CONNECTION_FACTORY_NAMESPACE_PROPERTY_NAME);
84633        if (connectionFactoryClass == null) {
85             try {
86621                connectionFactory = new DBConnectionFactoryImpl(connectionFactoryNamespace);
873            } catch (ConfigurationException e) {
883                throw new PersistenceConfigurationException(
89                     "The DBConnectionFactory encountered a misconfiguration issue.",
90                     e);
910            } catch (UnknownConnectionException e) {
920                throw new PersistenceConfigurationException(
93                     "The DBConnectionFactory encountered a misconfiguration issue.",
94                     e);
95618            }
96         } else {
9712            connectionFactory = (DBConnectionFactory) createInstance(connectionFactoryClass,
982                new Class[]{String.class}, new Object[]{connectionFactoryNamespace}, DBConnectionFactory.class);
99         }
100621        connectionName = Utils.lookupOptionalStringFromConfigManager(namespace, CONNECTION_NAME_PROPERTY_NAME);
101621    }
102  
103     /**
104      * This constructor will populate the connectionFactory and connectionName information from input parameters.
105      *
106      * @param connectionFactory DBConnectionFactory instance used to generate connections.
107      * @param connectionName The name of the connection used for persistence operations.
108      *
109      * @throws IllegalArgumentException if connectionFactory is <tt>null</tt>
110      */
11112    protected AbstractDBIndexPersistence(final DBConnectionFactory connectionFactory, final String connectionName) {
11212        if (connectionFactory == null) {
1133            throw new IllegalArgumentException("The parameter named [connectionFactory] was null.");
114         }
1159        this.connectionFactory = connectionFactory;
116         // simplify empty String to null
1179        this.connectionName = connectionName != null
118                               ? connectionName.trim().length() > 0
119                                 ? connectionName
120                                 : null
121                               : null;
1229    }
123  
124     /**
125      * Returns a new connection to be used for persistence. This method will obtain the connection from the
126      * connectionFactory using the connectionName alias.
127      *
128      * @return the transactional connection created
129      *
130      * @throws IndexPersistenceException If unable to obtain a Connection.
131      */
132     protected Connection getConnection() throws IndexPersistenceException {
133         try {
134806            final Connection connection = connectionName == null
135                                           ? connectionFactory.createConnection()
136                                           : connectionFactory.createConnection(connectionName);
137806            connection.setAutoCommit(false);
138806            return connection;
1390        } catch (DBConnectionException e) {
1400            throw new IndexPersistenceException(
141                 "Connecting to the database (connection name was [" + connectionName + "]) failed.", e);
1420        } catch (SQLException e) {
1430            throw new IndexPersistenceException("Initialization of connection parameters (autocommit) "
144                 + "failed on the connection obtained from DBConnectionFactory (connection name was ["
145                 + connectionName + "]).", e);
146         }
147     }
148  
149     /**
150      * Starts a transaction on the passed in connection.
151      *
152      * @param connection The Connection taking part in the transaction.
153      *
154      * @throws IndexPersistenceException If an error occurs during this process, or if the Connection does not support
155      * transactions.
156      * @throws IllegalArgumentException if connection is <tt>null</tt>
157      */
158     protected void beginTransaction(final Connection connection) throws IndexPersistenceException {
159154        if (connection == null) {
1601            throw new IllegalArgumentException("The parameter named [connection] was null.");
161         }
162  
163         // as stated by the designer this method currently does nothing
164153    }
165  
166     /**
167      * This method commits a transaction on the passed in connection. The connection is the closed.
168      *
169      * @param connection The Connection taking part in the transaction to be committed and closed
170      *
171      * @throws IndexPersistenceException If an error occurs during this process, or if the Connection does not support
172      * transactions
173      * @throws IllegalArgumentException if connection is <tt>null</tt>
174      */
175     protected void commitTransaction(final Connection connection) throws IndexPersistenceException {
176503        if (connection == null) {
1771            throw new IllegalArgumentException("The parameter named [connection] was null.");
178         }
179  
180         try {
181502            connection.commit();
1821        } catch (SQLException e) {
1831            throw new IndexPersistenceException("Error while committing the connection [" + connection + "]", e);
184         } finally {
185502            DatabaseUtils.closeSilently(connection);
186501        }
187501    }
188  
189     /**
190      * This method rolls back the transaction on the passed connection.
191      *
192      * @param connection The Connection taking part in the transaction to be rolled back and closed
193      *
194      * @throws IndexPersistenceException If an error occurs during this process, or if the Connection does not support
195      * transactions
196      * @throws IllegalArgumentException if connection is <tt>null</tt>
197      */
198     protected void rollbackTransaction(final Connection connection) throws IndexPersistenceException {
19918        if (connection == null) {
2001            throw new IllegalArgumentException("The parameter named [connection] was null.");
201         }
202  
203         try {
20417            connection.rollback();
2054        } catch (SQLException e) {
2064            throw new IndexPersistenceException("Error while rolling back the connection [" + connection + "]", e);
207         } finally {
20817            DatabaseUtils.closeSilently(connection);
20913        }
21013    }
211  
212     /**
213      * This method creates a new Object instance from the given class name. If the class could be loaded, a Constructor
214      * that has the signature specified is looked up, which is then called specifying the given initargs.
215      *
216      * @param classname the name of the implementation class to be instantiated
217      * @param constructorSignature the signature of the constructor to be called
218      * @param initargs the constructor arguments to be used upon invocation of the constructor retrieved
219      * @param expectedType the expected type of the instance created, will be checked after instantiation
220      *
221      * @return the instance created
222      *
223      * @throws PersistenceConfigurationException
224      * the class specified cannot be loaded,no public constructor with the signature
225      * specified does exist in the class or the constructor invocation throws an
226      * exception
227      * @throws IllegalArgumentException if any arg is <tt>null</tt>, or any String arg is an empty (trim'd) string or
228      * the init args do not match the given signature
229      */
230     private static Object createInstance(final String classname,
231                                          final Class[] constructorSignature,
232                                          final Object[] initargs,
233                                          final Class expectedType) throws PersistenceConfigurationException {
234         //arg checking is done in findConstructor
23512        final Constructor constructor = findConstructor(classname, initargs, expectedType, constructorSignature);
236  
237         //create instance
238         final Object instance;
239         try {
2403            instance = constructor.newInstance(initargs);
2410        } catch (Throwable t) {
242             // catch of Throwable is normally discouraged by the TC coding style, but
243             // as a lot of Errors can arise from a reflection invocation and these
244             // errors don't need to be let pass through this catch clause (as they
245             // definitely belong to the reflective invocation and not the normal program
246             // execution) all Throwables are caught here and
247             // wrapped into a ConfigurationException.
2480            throw new PersistenceConfigurationException("the implementation class [" + classname
249                 + "] could not be instantiated, constructor invocation failed.", t);
2503        }
2513        return instance;
252     }
253  
254     /**
255      * This method loads the class from the given class name. If the class could be loaded, a Constructor that has the
256      * signature specified is looked up.
257      *
258      * @param classname the name of the implementation class to be loaded
259      * @param constructorSignature the signature of the constructor to be fond
260      * @param initargs the constructor arguments to be used upon invocation of the constructor retrieved
261      * (for checking conformance with given signature)
262      * @param expectedType the expected type of the class loaded, if not assignable, ConfigurationException will
263      * be thrown
264      *
265      * @return the Constructor found
266      *
267      * @throws PersistenceConfigurationException
268      * the class specified cannot be loaded,no public constructor with the signature
269      * specified does exist in the class or the constructor invocation throws an
270      * exception
271      * @throws IllegalArgumentException if any arg is <tt>null</tt>, or any String arg is an empty (trim'd) string or
272      * the init args do not match the given signature or the constructor signature
273      * contains a <tt>null</tt> value
274      */
275     private static Constructor findConstructor(final String classname, final Object[] initargs,
276                                                final Class expectedType,
277                                                final Class[] constructorSignature)
278         throws PersistenceConfigurationException {
27912        if (classname == null) {
2800            throw new IllegalArgumentException("The parameter named [classname] was null.");
281         }
28212        if (classname.trim().length() == 0) {
2830            throw new IllegalArgumentException("The parameter named [classname] was an empty String.");
284         }
28512        if (initargs == null) {
2860            throw new IllegalArgumentException("The parameter named [initargs] was null.");
287         }
28812        if (expectedType == null) {
2890            throw new IllegalArgumentException("The parameter named [expectedType] was null.");
290         }
29112        if (constructorSignature == null) {
2920            throw new IllegalArgumentException("The parameter named [constructorSignature] was null.");
293         }
29412        checkArgsMatchSignature(constructorSignature, initargs);
295  
296         //lookup and load instance implementation class
297         final Class implClass;
298         try {
29912            implClass = Class.forName(classname);
3003        } catch (Throwable t1) {
301             // catch of Throwable is normally discouraged by the TC coding style, but
302             // as a lot of Errors can arise from a class load and these
303             // errors don't need to be let pass through this catch clause (as they
304             // definitely belong to the class load and not the normal program
305             // execution) all Throwables are caught here and
306             // wrapped into a ConfigurationException.
3073            throw new PersistenceConfigurationException("Unable to load implementation class [" + classname + "].", t1);
3089        }
309  
310         //check if class matches expected type
3119        if (!expectedType.isAssignableFrom(implClass)) {
3126            throw new PersistenceConfigurationException(
313                 "the implementation class [" + classname + "] is not of type [" + expectedType.getName() + "].");
314         }
315  
316         //find constructor
317         final Constructor constructor;
318         try {
3193            constructor = implClass.getConstructor(constructorSignature);
3200        } catch (NoSuchMethodException e) {
3210            throw new PersistenceConfigurationException("The implementation class [" + implClass .getName()
322                 + "] did not have a constructor with signature [" + Arrays.asList(constructorSignature).toString()
323                 + "].", e);
324  
3253        }
3263        return constructor;
327     }
328  
329     /**
330      * This method checks whether each element of the initargs is assignable to the type specified in the equivalent
331      * constructorSignature element, both arrays have same size and constructorSignature does not contain <tt>null</tt>
332      * values.
333      *
334      * @param constructorSignature the signature to check for match with initargs
335      * @param initargs the initargs to check for match with constructorSignature
336      *
337      * @throws IllegalArgumentException in case any of the checks fails and thus the given initargs cannot be used as
338      * args for a constructor of the given signature
339      */
340     private static void checkArgsMatchSignature(final Class[] constructorSignature, final Object[] initargs) {
34112        if (initargs.length != constructorSignature.length) {
3420            throw new IllegalArgumentException("The given constructor signature ([" + constructorSignature.length
343                 + "] args) and the given initargs ([" + initargs.length + "] args) have different length.");
344         }
34524        for (int i = 0; i < constructorSignature.length; i++) {
34612            final Class argType = constructorSignature[i];
34712            final Object argValue = initargs[i];
34812            if (argType == null) {
3490                throw new IllegalArgumentException(
350                     "The parameter named [constructorSignature] contained a null value.");
351             }
352  
353             // a null argument does match any type
35412            if (argValue != null) {
355                 // check if actual arg matches declared arg type of constructor signature
35612                if (!argType.isAssignableFrom(argValue.getClass())) {
3570                    throw new IllegalArgumentException("The given initArg element at position [" + i + "] is of type ["
358                         + argValue.getClass().getName()
359                         + "] which does not match the argument type specified in the constructor signature ["
360                         + argType.getName() + "] for that argument.");
361                 }
362             }
363         }
36412    }
365  
366 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.