/jboss-as-7.1.1.Final/cmp/src/main/java/org/jboss/as/cmp/jdbc/JDBCAbstractCreateCommand.java
Java | 303 lines | 214 code | 36 blank | 53 comment | 49 complexity | 24b248ebdad2a203753d8a9cca2a17e1 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
1/*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2011, Red Hat, Inc., and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22package org.jboss.as.cmp.jdbc;
23
24import java.lang.reflect.Method;
25import java.sql.Connection;
26import java.sql.PreparedStatement;
27import java.sql.SQLException;
28import java.util.ArrayList;
29import java.util.Date;
30import java.util.List;
31import javax.ejb.CreateException;
32import org.jboss.as.cmp.CmpMessages;
33import static org.jboss.as.cmp.CmpMessages.MESSAGES;
34import org.jboss.as.cmp.context.CmpEntityBeanContext;
35import org.jboss.as.cmp.jdbc.bridge.JDBCCMPFieldBridge;
36import org.jboss.as.cmp.jdbc.bridge.JDBCCMRFieldBridge;
37import org.jboss.as.cmp.jdbc.bridge.JDBCEntityBridge;
38import org.jboss.as.cmp.jdbc.bridge.JDBCFieldBridge;
39import org.jboss.as.cmp.jdbc.metadata.JDBCEntityCommandMetaData;
40import org.jboss.logging.Logger;
41import org.jboss.security.AuthenticationManager;
42
43/**
44 * Base class for create commands that drives the operation sequence.
45 *
46 * @author <a href="mailto:jeremy@boynes.com">Jeremy Boynes</a>
47 * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
48 */
49public abstract class JDBCAbstractCreateCommand implements JDBCCreateCommand {
50 protected Logger log;
51 protected boolean debug;
52 protected boolean trace;
53 protected JDBCEntityBridge entity;
54 protected AuthenticationManager securityManager;
55 protected boolean createAllowed;
56 protected SQLExceptionProcessor exceptionProcessor;
57 protected String insertSQL;
58 protected JDBCFieldBridge[] insertFields;
59 protected boolean insertAfterEjbPostCreate;
60
61 // Generated fields
62 private JDBCCMPFieldBridge createdPrincipal;
63 private JDBCCMPFieldBridge createdTime;
64 private JDBCCMPFieldBridge updatedPrincipal;
65 private JDBCCMPFieldBridge updatedTime;
66
67 public void init(JDBCStoreManager manager) {
68 log = Logger.getLogger(getClass().getName() + '.' + manager.getMetaData().getName());
69 debug = log.isDebugEnabled();
70 trace = log.isTraceEnabled();
71
72 entity = (JDBCEntityBridge) manager.getEntityBridge();
73 insertAfterEjbPostCreate = manager.getCmpConfig().isInsertAfterEjbPostCreate();
74
75 // set create allowed
76 createAllowed = true;
77 JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
78 for (int i = 0; i < pkFields.length; i++) {
79 if (pkFields[i].isReadOnly()) {
80 createAllowed = false;
81 log.debug("Create will not be allowed because pk field "
82 + pkFields[i].getFieldName() + "is read only.");
83 break;
84 }
85 }
86
87 initGeneratedFields();
88
89 JDBCEntityCommandMetaData entityCommand = manager.getMetaData().getEntityCommand();
90 if (entityCommand == null) {
91 throw MESSAGES.entityCommandIsNull();
92 }
93 initEntityCommand(entityCommand);
94
95 initInsertFields();
96 initInsertSQL();
97 }
98
99 protected void initEntityCommand(JDBCEntityCommandMetaData entityCommand) {
100 exceptionProcessor = null;
101 }
102
103 public Object execute(Method m, Object[] args, CmpEntityBeanContext ctx) throws CreateException {
104 // TODO: implement this logic nicer
105 if (insertAfterEjbPostCreate) {
106 if (!JDBCEntityBridge.isEjbCreateDone(ctx)) {
107 checkCreateAllowed();
108 generateFields(ctx);
109 JDBCEntityBridge.setEjbCreateDone(ctx);
110 } else {
111 beforeInsert(ctx);
112 performInsert(ctx);
113 afterInsert(ctx);
114 JDBCEntityBridge.setCreated(ctx);
115 }
116 } else {
117 checkCreateAllowed();
118 generateFields(ctx);
119 beforeInsert(ctx);
120 performInsert(ctx);
121 afterInsert(ctx);
122 JDBCEntityBridge.setCreated(ctx);
123 }
124 return getPrimaryKey(ctx);
125 }
126
127 protected void checkCreateAllowed() throws CreateException {
128 if (!createAllowed) {
129 throw MESSAGES.creationNotAllowedPKReadOnly();
130 }
131 }
132
133 protected JDBCCMPFieldBridge getGeneratedPKField() {
134 // extract the pk field to be generated
135 JDBCCMPFieldBridge pkField = null;
136 JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
137 for (int i = 0; i < pkFields.length; ++i) {
138 if (pkField != null)
139 throw MESSAGES.generationOnlySupportedWithSinglePK();
140 pkField = (JDBCCMPFieldBridge) pkFields[i];
141 }
142 return pkField;
143 }
144
145 protected void initGeneratedFields() {
146 createdPrincipal = entity.getCreatedPrincipalField();
147 if (securityManager == null && createdPrincipal != null) {
148 throw MESSAGES.noSecurityDomainForCreatedBy();
149 }
150 updatedPrincipal = entity.getUpdatedPrincipalField();
151 if (securityManager == null && updatedPrincipal != null) {
152 throw MESSAGES.noSecurityDomainForCreatedBy();
153 }
154 createdTime = entity.getCreatedTimeField();
155 updatedTime = entity.getUpdatedTimeField();
156 }
157
158 protected void generateFields(CmpEntityBeanContext ctx) throws CreateException {
159 // Audit principal fields
160 if (securityManager != null) {
161 String principalName = ctx.getCallerPrincipal().getName();
162 if (createdPrincipal != null && createdPrincipal.getInstanceValue(ctx) == null) {
163 createdPrincipal.setInstanceValue(ctx, principalName);
164 }
165 /*
166 if(updatedPrincipal != null && updatedPrincipal.getInstanceValue(ctx) == null)
167 {
168 updatedPrincipal.setInstanceValue(ctx, principalName);
169 }
170 */
171 }
172
173 // Audit time fields
174 Date date = null;
175 if (createdTime != null && createdTime.getInstanceValue(ctx) == null) {
176 date = new Date();
177 createdTime.setInstanceValue(ctx, date);
178 }
179 /*
180 if(updatedTime != null && updatedTime.getInstanceValue(ctx) == null)
181 {
182 if(date == null)
183 date = new Date();
184 updatedTime.setInstanceValue(ctx, date);
185 }
186 */
187 }
188
189 protected void initInsertFields() {
190 JDBCFieldBridge[] fields = entity.getTableFields();
191 List insertFieldsList = new ArrayList(fields.length);
192 for (int i = 0; i < fields.length; i++) {
193 JDBCFieldBridge field = fields[i];
194 if (isInsertField(field))
195 insertFieldsList.add(field);
196 }
197
198 insertFields = (JDBCFieldBridge[]) insertFieldsList.toArray(new JDBCFieldBridge[insertFieldsList.size()]);
199 }
200
201 protected boolean isInsertField(JDBCFieldBridge field) {
202 boolean result =
203 !(field instanceof JDBCCMRFieldBridge)
204 && field.getJDBCType() != null
205 && !field.isReadOnly();
206 if (field instanceof JDBCCMPFieldBridge)
207 result = result && !((JDBCCMPFieldBridge) field).isRelationTableField();
208 return result;
209 }
210
211 protected void initInsertSQL() {
212 StringBuffer sql = new StringBuffer(250);
213 sql.append(SQLUtil.INSERT_INTO)
214 .append(entity.getQualifiedTableName())
215 .append(" (");
216
217 SQLUtil.getColumnNamesClause(insertFields, sql);
218
219 sql.append(')')
220 .append(SQLUtil.VALUES).append('(');
221 SQLUtil.getValuesClause(insertFields, sql)
222 .append(')');
223 insertSQL = sql.toString();
224
225 if (debug)
226 log.debug("Insert Entity SQL: " + insertSQL);
227 }
228
229 protected void beforeInsert(CmpEntityBeanContext ctx) throws CreateException {
230 }
231
232 protected void performInsert(CmpEntityBeanContext ctx) throws CreateException {
233 Connection c = null;
234 PreparedStatement ps = null;
235 boolean throwRuntimeExceptions = entity.getMetaData().getThrowRuntimeExceptions();
236
237 // if metadata is true, the getConnection is done inside
238 // its own try catch block to throw a runtime exception (EJBException)
239 if (throwRuntimeExceptions) {
240 try {
241 c = entity.getDataSource().getConnection();
242 } catch (SQLException sqle) {
243 javax.ejb.EJBException ejbe = new javax.ejb.EJBException("Could not get a connection; " + sqle);
244 ejbe.initCause(sqle);
245 throw ejbe;
246 }
247 }
248
249 try {
250 if (log.isDebugEnabled()) {
251 log.debug("Executing SQL: " + insertSQL);
252 }
253
254
255 // if metadata is false, the getConnection is done inside this try catch block
256 if (!throwRuntimeExceptions) {
257 c = entity.getDataSource().getConnection();
258 }
259 ps = prepareStatement(c, insertSQL, ctx);
260
261 // set the parameters
262 int index = 1;
263 for (int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd) {
264 index = insertFields[fieldInd].setInstanceParameters(ps, index, ctx);
265 }
266
267 // execute statement
268 int rowsAffected = executeInsert(index, ps, ctx);
269 if (rowsAffected != 1) {
270 throw CmpMessages.MESSAGES.expectedOneRow(rowsAffected, ctx.getPrimaryKey());
271 }
272 } catch (SQLException e) {
273 if (exceptionProcessor != null && exceptionProcessor.isDuplicateKey(e)) {
274 throw CmpMessages.MESSAGES.uniqueKeyViolationInvalidFk(ctx.getPrimaryKey());
275 } else {
276 throw CmpMessages.MESSAGES.couldNotCreateEntity(e);
277 }
278 } finally {
279 JDBCUtil.safeClose(ps);
280 JDBCUtil.safeClose(c);
281 }
282
283 // Mark the inserted fields as clean.
284 for (int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd) {
285 insertFields[fieldInd].setClean(ctx);
286 }
287 }
288
289 protected PreparedStatement prepareStatement(Connection c, String sql, CmpEntityBeanContext ctx) throws SQLException {
290 return c.prepareStatement(sql);
291 }
292
293 protected int executeInsert(int paramIndex, PreparedStatement ps, CmpEntityBeanContext ctx) throws SQLException {
294 return ps.executeUpdate();
295 }
296
297 protected void afterInsert(CmpEntityBeanContext ctx) throws CreateException {
298 }
299
300 protected Object getPrimaryKey(CmpEntityBeanContext ctx) {
301 return entity.extractPrimaryKeyFromInstance(ctx);
302 }
303}