KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > jdbc > ProcedureAction


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.access.jdbc;
21
22 import java.sql.CallableStatement JavaDoc;
23 import java.sql.Connection JavaDoc;
24 import java.sql.ResultSet JavaDoc;
25 import java.sql.SQLException JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import org.apache.cayenne.CayenneRuntimeException;
32 import org.apache.cayenne.access.OperationObserver;
33 import org.apache.cayenne.access.QueryLogger;
34 import org.apache.cayenne.access.trans.ProcedureTranslator;
35 import org.apache.cayenne.access.types.ExtendedType;
36 import org.apache.cayenne.dba.DbAdapter;
37 import org.apache.cayenne.map.EntityResolver;
38 import org.apache.cayenne.map.Procedure;
39 import org.apache.cayenne.map.ProcedureParameter;
40 import org.apache.cayenne.query.ProcedureQuery;
41
42 /**
43  * A SQLAction that runs a stored procedure. Note that ProcedureAction has internal state
44  * and is not thread-safe.
45  *
46  * @since 1.2
47  * @author Andrus Adamchik
48  */

49 public class ProcedureAction extends BaseSQLAction {
50
51     protected ProcedureQuery query;
52
53     /**
54      * Holds a number of ResultSets processed by the action. This value is reset to zero
55      * on every "performAction" call.
56      */

57     protected int processedResultSets;
58
59     public ProcedureAction(ProcedureQuery query, DbAdapter adapter,
60             EntityResolver entityResolver) {
61         super(adapter, entityResolver);
62         this.query = query;
63     }
64
65     public void performAction(Connection JavaDoc connection, OperationObserver observer)
66             throws SQLException JavaDoc, Exception JavaDoc {
67
68         processedResultSets = 0;
69
70         ProcedureTranslator transl = createTranslator(connection);
71
72         CallableStatement JavaDoc statement = (CallableStatement JavaDoc) transl.createStatement();
73
74         try {
75             // stored procedure may contain a mixture of update counts and result sets,
76
// and out parameters. Read out parameters first, then
77
// iterate until we exhaust all results
78

79             // TODO: andrus, 4/2/2007 - according to the docs we should store the boolean
80
// return value of this method and avoid calling 'getMoreResults' if it is true.
81
// some db's handle this well, some don't (MySQL).
82
statement.execute();
83
84             // read out parameters
85
readProcedureOutParameters(statement, observer);
86
87             // read the rest of the query
88
while (true) {
89                 if (statement.getMoreResults()) {
90                     ResultSet JavaDoc rs = statement.getResultSet();
91
92                     try {
93                         RowDescriptor descriptor = describeResultSet(
94                                 rs,
95                                 processedResultSets++);
96                         readResultSet(rs, descriptor, query, observer);
97                     }
98                     finally {
99                         try {
100                             rs.close();
101                         }
102                         catch (SQLException JavaDoc ex) {
103                         }
104                     }
105                 }
106                 else {
107                     int updateCount = statement.getUpdateCount();
108                     if (updateCount == -1) {
109                         break;
110                     }
111                     QueryLogger.logUpdateCount(updateCount);
112                     observer.nextCount(query, updateCount);
113                 }
114             }
115         }
116         finally {
117             try {
118                 statement.close();
119             }
120             catch (SQLException JavaDoc ex) {
121
122             }
123         }
124     }
125
126     /**
127      * Returns the ProcedureTranslator to use for this ProcedureAction.
128      *
129      * @param connection JDBC connection
130      */

131     protected ProcedureTranslator createTranslator(Connection JavaDoc connection) {
132         ProcedureTranslator translator = new ProcedureTranslator();
133         translator.setAdapter(getAdapter());
134         translator.setQuery(query);
135         translator.setEntityResolver(getEntityResolver());
136         translator.setConnection(connection);
137         return translator;
138     }
139
140     /**
141      * Creates a RowDescriptor for result set.
142      *
143      * @param resultSet JDBC ResultSet
144      * @param setIndex a zero-based index of the ResultSet in the query results.
145      */

146     protected RowDescriptor describeResultSet(ResultSet JavaDoc resultSet, int setIndex) {
147         if (setIndex < 0) {
148             throw new IllegalArgumentException JavaDoc(
149                     "Expected a non-negative result set index. Got: " + setIndex);
150         }
151
152         List JavaDoc descriptors = query.getResultDescriptors();
153
154         if (descriptors.isEmpty()) {
155             // failover to default JDBC result descriptor
156
return new RowDescriptor(resultSet, getAdapter().getExtendedTypes());
157         }
158
159         // if one result is described, all of them must be present...
160
if (setIndex >= descriptors.size() || descriptors.get(setIndex) == null) {
161             throw new CayenneRuntimeException("No descriptor for result set at index '"
162                     + setIndex
163                     + "' configured.");
164         }
165
166         ColumnDescriptor[] columns = (ColumnDescriptor[]) descriptors.get(setIndex);
167         return new RowDescriptor(columns, getAdapter().getExtendedTypes());
168     }
169
170     /**
171      * Returns stored procedure for an internal query.
172      */

173     protected Procedure getProcedure() {
174         return getEntityResolver().lookupProcedure(query);
175     }
176
177     /**
178      * Helper method that reads OUT parameters of a CallableStatement.
179      */

180     protected void readProcedureOutParameters(
181             CallableStatement JavaDoc statement,
182             OperationObserver delegate) throws SQLException JavaDoc, Exception JavaDoc {
183
184         long t1 = System.currentTimeMillis();
185
186         // build result row...
187
Map JavaDoc result = null;
188         List JavaDoc parameters = getProcedure().getCallParameters();
189         for (int i = 0; i < parameters.size(); i++) {
190             ProcedureParameter parameter = (ProcedureParameter) parameters.get(i);
191
192             if (!parameter.isOutParam()) {
193                 continue;
194             }
195
196             if (result == null) {
197                 result = new HashMap JavaDoc();
198             }
199
200             ColumnDescriptor descriptor = new ColumnDescriptor(parameter);
201             ExtendedType type = getAdapter().getExtendedTypes().getRegisteredType(
202                     descriptor.getJavaClass());
203             Object JavaDoc val = type.materializeObject(statement, i + 1, descriptor
204                     .getJdbcType());
205
206             result.put(descriptor.getLabel(), val);
207         }
208
209         if (result != null && !result.isEmpty()) {
210             // treat out parameters as a separate data row set
211
QueryLogger.logSelectCount(1, System.currentTimeMillis() - t1);
212             delegate.nextDataRows(query, Collections.singletonList(result));
213         }
214     }
215 }
216
Popular Tags