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 package org.apache.openjpa.jdbc.kernel;
20
21 import java.sql.Connection;
22 import java.sql.PreparedStatement;
23 import java.sql.SQLException;
24 import java.util.Collection;
25 import java.util.LinkedList;
26
27 import org.apache.openjpa.jdbc.meta.ClassMapping;
28 import org.apache.openjpa.jdbc.schema.Column;
29 import org.apache.openjpa.jdbc.sql.DBDictionary;
30 import org.apache.openjpa.jdbc.sql.Row;
31 import org.apache.openjpa.jdbc.sql.RowImpl;
32 import org.apache.openjpa.jdbc.sql.SQLExceptions;
33 import org.apache.openjpa.kernel.OpenJPAStateManager;
34 import org.apache.openjpa.lib.util.Localizer;
35 import org.apache.openjpa.util.ApplicationIds;
36 import org.apache.openjpa.util.OpenJPAException;
37 import org.apache.openjpa.util.OptimisticException;
38
39 /**
40 * Basic prepared statement manager implementation.
41 *
42 * @author Abe White
43 */
44 public class PreparedStatementManagerImpl
45 implements PreparedStatementManager {
46
47 private final static Localizer _loc = Localizer
48 .forPackage(PreparedStatementManagerImpl.class);
49
50 protected final JDBCStore _store;
51 protected final Connection _conn;
52 protected final DBDictionary _dict;
53
54 // track exceptions
55 protected final Collection _exceptions = new LinkedList();
56
57 /**
58 * Constructor. Supply connection.
59 */
60 public PreparedStatementManagerImpl(JDBCStore store, Connection conn) {
61 _store = store;
62 _dict = store.getDBDictionary();
63 _conn = conn;
64 }
65
66 public Collection getExceptions() {
67 return _exceptions;
68 }
69
70 public void flush(RowImpl row) {
71 try {
72 flushInternal(row);
73 } catch (SQLException se) {
74 _exceptions.add(SQLExceptions.getStore(se, _dict));
75 } catch (OpenJPAException ke) {
76 _exceptions.add(ke);
77 }
78 }
79
80 /**
81 * Flush the given row.
82 */
83 protected void flushInternal(RowImpl row) throws SQLException {
84 // can't batch rows with auto-inc columns
85 Column[] autoAssign = null;
86 if (row.getAction() == Row.ACTION_INSERT)
87 autoAssign = row.getTable().getAutoAssignedColumns();
88
89 flushAndUpdate(row);
90
91 // set auto assign values
92 if (autoAssign != null && autoAssign.length > 0
93 && row.getPrimaryKey() != null) {
94 OpenJPAStateManager sm = row.getPrimaryKey();
95 ClassMapping mapping = (ClassMapping) sm.getMetaData();
96 Object val;
97 for (int i = 0; i < autoAssign.length; i++) {
98 val = _dict.getGeneratedKey(autoAssign[i], _conn);
99 mapping.assertJoinable(autoAssign[i]).setAutoAssignedValue(sm,
100 _store, autoAssign[i], val);
101 }
102 sm.setObjectId(
103 ApplicationIds.create(sm.getPersistenceCapable(), mapping));
104 }
105 }
106
107 /**
108 * Flush the given row immediately.
109 */
110 protected void flushAndUpdate(RowImpl row)
111 throws SQLException {
112 // prepare statement
113 String sql = row.getSQL(_dict);
114 PreparedStatement stmnt = prepareStatement(sql);
115
116 // setup parameters and execute statement
117 if (stmnt != null)
118 row.flush(stmnt, _dict, _store);
119 try {
120 int count = executeUpdate(stmnt, sql, row);
121 if (count != 1) {
122 Object failed = row.getFailedObject();
123 if (failed != null)
124 _exceptions.add(new OptimisticException(failed));
125 else if (row.getAction() == Row.ACTION_INSERT)
126 throw new SQLException(_loc.get(
127 "update-failed-no-failed-obj", String.valueOf(count),
128 sql).getMessage());
129 }
130 } catch (SQLException se) {
131 throw SQLExceptions.getStore(se, row.getFailedObject(), _dict);
132 } finally {
133 if (stmnt != null) {
134 try {
135 stmnt.close();
136 } catch (SQLException se) {
137 }
138 }
139 }
140 }
141
142 public void flush() {
143 }
144
145 /**
146 * This method is to provide override for non-JDBC or JDBC-like
147 * implementation of executing update.
148 */
149 protected int executeUpdate(PreparedStatement stmnt, String sql,
150 RowImpl row) throws SQLException {
151 return stmnt.executeUpdate();
152 }
153
154 /**
155 * This method is to provide override for non-JDBC or JDBC-like
156 * implementation of preparing statement.
157 */
158 protected PreparedStatement prepareStatement(String sql)
159 throws SQLException {
160 return _conn.prepareStatement(sql);
161 }
162 }