KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jca > cci > core > CciTemplate


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.jca.cci.core;
18
19 import java.sql.SQLException JavaDoc;
20
21 import javax.resource.NotSupportedException JavaDoc;
22 import javax.resource.ResourceException JavaDoc;
23 import javax.resource.cci.Connection JavaDoc;
24 import javax.resource.cci.ConnectionFactory JavaDoc;
25 import javax.resource.cci.ConnectionSpec JavaDoc;
26 import javax.resource.cci.IndexedRecord JavaDoc;
27 import javax.resource.cci.Interaction JavaDoc;
28 import javax.resource.cci.InteractionSpec JavaDoc;
29 import javax.resource.cci.MappedRecord JavaDoc;
30 import javax.resource.cci.Record JavaDoc;
31 import javax.resource.cci.RecordFactory JavaDoc;
32 import javax.resource.cci.ResultSet JavaDoc;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 import org.springframework.dao.DataAccessException;
38 import org.springframework.dao.DataAccessResourceFailureException;
39 import org.springframework.jca.cci.CannotCreateRecordException;
40 import org.springframework.jca.cci.CciOperationNotSupportedException;
41 import org.springframework.jca.cci.InvalidResultSetAccessException;
42 import org.springframework.jca.cci.RecordTypeNotSupportedException;
43 import org.springframework.jca.cci.connection.ConnectionFactoryUtils;
44 import org.springframework.jca.cci.connection.NotSupportedRecordFactory;
45 import org.springframework.util.Assert;
46
47 /**
48  * <b>This is the central class in the CCI core package.</b>
49  * It simplifies the use of CCI and helps to avoid common errors.
50  * It executes core CCI workflow, leaving application code to provide parameters
51  * to CCI and extract results. This class executes EIS queries or updates,
52  * catching ResourceExceptions and translating them to the generic exception
53  * hierarchy defined in the <code>org.springframework.dao</code> package.
54  *
55  * <p>Code using this class can pass in and receive {@link javax.resource.cci.Record}
56  * instances, or alternatively implement callback interfaces for creating input
57  * Records and extracting result objects from output Records (or CCI ResultSets).
58  *
59  * <p>Can be used within a service implementation via direct instantiation
60  * with a ConnectionFactory reference, or get prepared in an application context
61  * and given to services as bean reference. Note: The ConnectionFactory should
62  * always be configured as a bean in the application context, in the first case
63  * given to the service directly, in the second case to the prepared template.
64  *
65  * @author Thierry Templier
66  * @author Juergen Hoeller
67  * @since 1.2
68  * @see RecordCreator
69  * @see RecordExtractor
70  * @see org.springframework.dao
71  * @see org.springframework.jca.cci.connection
72  * @see org.springframework.jca.cci.object
73  */

74 public class CciTemplate implements CciOperations {
75
76     private final Log logger = LogFactory.getLog(getClass());
77
78     private ConnectionFactory JavaDoc connectionFactory;
79
80     private ConnectionSpec JavaDoc connectionSpec;
81
82     private RecordCreator outputRecordCreator;
83
84
85     /**
86      * Construct a new CciTemplate for bean usage.
87      * <p>Note: The ConnectionFactory has to be set before using the instance.
88      * @see #setConnectionFactory
89      */

90     public CciTemplate() {
91     }
92
93     /**
94      * Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
95      * Note: This will trigger eager initialization of the exception translator.
96      * @param connectionFactory JCA ConnectionFactory to obtain Connections from
97      */

98     public CciTemplate(ConnectionFactory JavaDoc connectionFactory) {
99         setConnectionFactory(connectionFactory);
100         afterPropertiesSet();
101     }
102
103     /**
104      * Construct a new CciTemplate, given a ConnectionFactory to obtain Connections from.
105      * Note: This will trigger eager initialization of the exception translator.
106      * @param connectionFactory JCA ConnectionFactory to obtain Connections from
107      * @param connectionSpec the CCI ConnectionSpec to obtain Connections for
108      * (may be <code>null</code>)
109      */

110     public CciTemplate(ConnectionFactory JavaDoc connectionFactory, ConnectionSpec JavaDoc connectionSpec) {
111         setConnectionFactory(connectionFactory);
112         setConnectionSpec(connectionSpec);
113         afterPropertiesSet();
114     }
115
116
117     /**
118      * Set the CCI ConnectionFactory to obtain Connections from.
119      */

120     public void setConnectionFactory(ConnectionFactory JavaDoc connectionFactory) {
121         this.connectionFactory = connectionFactory;
122     }
123
124     /**
125      * Return the CCI ConnectionFactory used by this template.
126      */

127     public ConnectionFactory JavaDoc getConnectionFactory() {
128         return this.connectionFactory;
129     }
130
131     /**
132      * Set the CCI ConnectionSpec that this template instance is
133      * supposed to obtain Connections for.
134      */

135     public void setConnectionSpec(ConnectionSpec JavaDoc connectionSpec) {
136         this.connectionSpec = connectionSpec;
137     }
138
139     /**
140      * Return the CCI ConnectionSpec used by this template, if any.
141      */

142     public ConnectionSpec JavaDoc getConnectionSpec() {
143         return this.connectionSpec;
144     }
145
146     /**
147      * Set a RecordCreator that should be used for creating default output Records.
148      * <p>Default is none: When no explicit output Record gets passed into an
149      * <code>execute</code> method, CCI's <code>Interaction.execute</code> variant
150      * that returns an output Record will be called.
151      * <p>Specify a RecordCreator here if you always need to call CCI's
152      * <code>Interaction.execute</code> variant with a passed-in output Record.
153      * Unless there is an explicitly specified output Record, CciTemplate will
154      * then invoke this RecordCreator to create a default output Record instance.
155      * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
156      * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
157      */

158     public void setOutputRecordCreator(RecordCreator creator) {
159         outputRecordCreator = creator;
160     }
161
162     /**
163      * Return a RecordCreator that should be used for creating default output Records.
164      */

165     public RecordCreator getOutputRecordCreator() {
166         return this.outputRecordCreator;
167     }
168
169     public void afterPropertiesSet() {
170         if (getConnectionFactory() == null) {
171             throw new IllegalArgumentException JavaDoc("Property 'connectionFactory' is required");
172         }
173     }
174
175
176     /**
177      * Create a template derived from this template instance,
178      * inheriting the ConnectionFactory and other settings but
179      * overriding the ConnectionSpec used for obtaining Connections.
180      * @param connectionSpec the CCI ConnectionSpec that the derived template
181      * instance is supposed to obtain Connections for
182      * @return the derived template instance
183      * @see #setConnectionSpec
184      */

185     public CciTemplate getDerivedTemplate(ConnectionSpec JavaDoc connectionSpec) {
186         CciTemplate derived = new CciTemplate();
187         derived.setConnectionFactory(getConnectionFactory());
188         derived.setConnectionSpec(connectionSpec);
189         derived.setOutputRecordCreator(getOutputRecordCreator());
190         return derived;
191     }
192
193
194     public Object JavaDoc execute(ConnectionCallback action) throws DataAccessException {
195         Assert.notNull(action, "Callback object must not be null");
196
197         Connection JavaDoc con = ConnectionFactoryUtils.getConnection(getConnectionFactory(), getConnectionSpec());
198         try {
199             return action.doInConnection(con, getConnectionFactory());
200         }
201         catch (NotSupportedException JavaDoc ex) {
202             throw new CciOperationNotSupportedException("CCI operation not supported by connector", ex);
203         }
204         catch (ResourceException JavaDoc ex) {
205             throw new DataAccessResourceFailureException("CCI operation failed", ex);
206         }
207         catch (SQLException JavaDoc ex) {
208             throw new InvalidResultSetAccessException("Parsing of CCI ResultSet failed", ex);
209         }
210         finally {
211             ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
212         }
213     }
214
215     public Object JavaDoc execute(final InteractionCallback action) throws DataAccessException {
216         Assert.notNull(action, "Callback object must not be null");
217
218         return execute(new ConnectionCallback() {
219             public Object JavaDoc doInConnection(Connection JavaDoc connection, ConnectionFactory JavaDoc connectionFactory)
220                     throws ResourceException JavaDoc, SQLException JavaDoc, DataAccessException {
221
222                 Interaction JavaDoc interaction = connection.createInteraction();
223                 try {
224                     return action.doInInteraction(interaction, connectionFactory);
225                 }
226                 finally {
227                     closeInteraction(interaction);
228                 }
229             }
230         });
231     }
232
233     public Record JavaDoc execute(InteractionSpec JavaDoc spec, Record JavaDoc inputRecord) throws DataAccessException {
234         return (Record JavaDoc) doExecute(spec, inputRecord, null, null);
235     }
236
237     public void execute(InteractionSpec JavaDoc spec, Record JavaDoc inputRecord, Record JavaDoc outputRecord) throws DataAccessException {
238         doExecute(spec, inputRecord, outputRecord, null);
239     }
240
241     public Record JavaDoc execute(InteractionSpec JavaDoc spec, RecordCreator inputCreator) throws DataAccessException {
242         return (Record JavaDoc) doExecute(spec, createRecord(inputCreator), null, null);
243     }
244
245     public Object JavaDoc execute(InteractionSpec JavaDoc spec, Record JavaDoc inputRecord, RecordExtractor outputExtractor)
246             throws DataAccessException {
247
248         return doExecute(spec, inputRecord, null, outputExtractor);
249     }
250
251     public Object JavaDoc execute(InteractionSpec JavaDoc spec, RecordCreator inputCreator, RecordExtractor outputExtractor)
252             throws DataAccessException {
253
254         return doExecute(spec, createRecord(inputCreator), null, outputExtractor);
255     }
256
257     /**
258      * Execute the specified interaction on an EIS with CCI.
259      * All other interaction execution methods go through this.
260      * @param spec the CCI InteractionSpec instance that defines
261      * the interaction (connector-specific)
262      * @param inputRecord the input record
263      * @param outputRecord output record (can be <code>null</code>)
264      * @param outputExtractor object to convert the output record to a result object
265      * @return the output data extracted with the RecordExtractor object
266      * @throws DataAccessException if there is any problem
267      */

268     protected Object JavaDoc doExecute(
269             final InteractionSpec JavaDoc spec, final Record JavaDoc inputRecord, final Record JavaDoc outputRecord,
270             final RecordExtractor outputExtractor) throws DataAccessException {
271
272         return execute(new InteractionCallback() {
273             public Object JavaDoc doInInteraction(Interaction JavaDoc interaction, ConnectionFactory JavaDoc connectionFactory)
274                     throws ResourceException JavaDoc, SQLException JavaDoc, DataAccessException {
275
276                 Record JavaDoc outputRecordToUse = outputRecord;
277                 try {
278                     if (outputRecord != null || getOutputRecordCreator() != null) {
279                         // Use the CCI execute method with output record as parameter.
280
if (outputRecord == null) {
281                             RecordFactory JavaDoc recordFactory = getRecordFactory(connectionFactory);
282                             outputRecordToUse = getOutputRecordCreator().createRecord(recordFactory);
283                         }
284                         interaction.execute(spec, inputRecord, outputRecordToUse);
285                     }
286                     else {
287                         outputRecordToUse = interaction.execute(spec, inputRecord);
288                     }
289                     if (outputExtractor != null) {
290                         return outputExtractor.extractData(outputRecordToUse);
291                     }
292                     else {
293                         return outputRecordToUse;
294                     }
295                 }
296                 finally {
297                     if (outputRecordToUse instanceof ResultSet JavaDoc) {
298                         closeResultSet((ResultSet JavaDoc) outputRecordToUse);
299                     }
300                 }
301             }
302         });
303     }
304
305
306     /**
307      * Create an indexed Record through the ConnectionFactory's RecordFactory.
308      * @param name the name of the record
309      * @return the Record
310      * @throws DataAccessException if creation of the Record failed
311      * @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
312      * @see javax.resource.cci.RecordFactory#createIndexedRecord(String)
313      */

314     public IndexedRecord JavaDoc createIndexedRecord(String JavaDoc name) throws DataAccessException {
315         try {
316             RecordFactory JavaDoc recordFactory = getRecordFactory(getConnectionFactory());
317             return recordFactory.createIndexedRecord(name);
318         }
319         catch (NotSupportedException JavaDoc ex) {
320             throw new RecordTypeNotSupportedException("Creation of indexed Record not supported by connector", ex);
321         }
322         catch (ResourceException JavaDoc ex) {
323             throw new CannotCreateRecordException("Creation of indexed Record failed", ex);
324         }
325     }
326
327     /**
328      * Create a mapped Record from the ConnectionFactory's RecordFactory.
329      * @param name record name
330      * @return the Record
331      * @throws DataAccessException if creation of the Record failed
332      * @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
333      * @see javax.resource.cci.RecordFactory#createMappedRecord(String)
334      */

335     public MappedRecord JavaDoc createMappedRecord(String JavaDoc name) throws DataAccessException {
336         try {
337             RecordFactory JavaDoc recordFactory = getRecordFactory(getConnectionFactory());
338             return recordFactory.createMappedRecord(name);
339         }
340         catch (NotSupportedException JavaDoc ex) {
341             throw new RecordTypeNotSupportedException("Creation of mapped Record not supported by connector", ex);
342         }
343         catch (ResourceException JavaDoc ex) {
344             throw new CannotCreateRecordException("Creation of mapped Record failed", ex);
345         }
346     }
347
348     /**
349      * Invoke the given RecordCreator, converting JCA ResourceExceptions
350      * to Spring's DataAccessException hierarchy.
351      * @param recordCreator the RecordCreator to invoke
352      * @return the created Record
353      * @throws DataAccessException if creation of the Record failed
354      * @see #getRecordFactory(javax.resource.cci.ConnectionFactory)
355      * @see RecordCreator#createRecord(javax.resource.cci.RecordFactory)
356      */

357     protected Record JavaDoc createRecord(RecordCreator recordCreator) throws DataAccessException {
358         try {
359             RecordFactory JavaDoc recordFactory = getRecordFactory(getConnectionFactory());
360             return recordCreator.createRecord(recordFactory);
361         }
362         catch (NotSupportedException JavaDoc ex) {
363             throw new RecordTypeNotSupportedException(
364                     "Creation of the desired Record type not supported by connector", ex);
365         }
366         catch (ResourceException JavaDoc ex) {
367             throw new CannotCreateRecordException("Creation of the desired Record failed", ex);
368         }
369     }
370
371     /**
372      * Return a RecordFactory for the given ConnectionFactory.
373      * <p>Default implementation returns the connector's RecordFactory if
374      * available, falling back to a NotSupportedRecordFactory placeholder.
375      * This allows to invoke a RecordCreator callback with a non-null
376      * RecordFactory reference in any case.
377      * @param connectionFactory the CCI ConnectionFactory
378      * @return the CCI RecordFactory for the ConnectionFactory
379      * @throws ResourceException if thrown by CCI methods
380      * @see org.springframework.jca.cci.connection.NotSupportedRecordFactory
381      */

382     protected RecordFactory JavaDoc getRecordFactory(ConnectionFactory JavaDoc connectionFactory) throws ResourceException JavaDoc {
383         try {
384             return getConnectionFactory().getRecordFactory();
385         }
386         catch (NotSupportedException JavaDoc ex) {
387             return new NotSupportedRecordFactory();
388         }
389     }
390
391
392     /**
393      * Close the given CCI Interaction and ignore any thrown exception.
394      * This is useful for typical finally blocks in manual CCI code.
395      * @param interaction the CCI Interaction to close
396      * @see javax.resource.cci.Interaction#close()
397      */

398     private void closeInteraction(Interaction JavaDoc interaction) {
399         if (interaction != null) {
400             try {
401                 interaction.close();
402             }
403             catch (ResourceException JavaDoc ex) {
404                 logger.debug("Could not close CCI Interaction", ex);
405             }
406             catch (Throwable JavaDoc ex) {
407                 // We don't trust the CCI driver: It might throw RuntimeException or Error.
408
logger.debug("Unexpected exception on closing CCI Interaction", ex);
409             }
410         }
411     }
412
413     /**
414      * Close the given CCI ResultSet and ignore any thrown exception.
415      * This is useful for typical finally blocks in manual CCI code.
416      * @param resultSet the CCI ResultSet to close
417      * @see javax.resource.cci.ResultSet#close()
418      */

419     private void closeResultSet(ResultSet JavaDoc resultSet) {
420         if (resultSet != null) {
421             try {
422                 resultSet.close();
423             }
424             catch (SQLException JavaDoc ex) {
425                 logger.debug("Could not close CCI ResultSet", ex);
426             }
427             catch (Throwable JavaDoc ex) {
428                 // We don't trust the CCI driver: It might throw RuntimeException or Error.
429
logger.debug("Unexpected exception on closing CCI ResultSet", ex);
430             }
431         }
432     }
433
434 }
435
Popular Tags