/jboss-as-7.1.1.Final/cmp/src/main/java/org/jboss/as/cmp/jdbc/JDBCStoreEntityCommand.java
Java | 156 lines | 94 code | 15 blank | 47 comment | 16 complexity | ec2b75c760ed70075010ac8e9b15aca2 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.sql.Connection;
25import java.sql.PreparedStatement;
26import javax.ejb.EJBException;
27import org.jboss.as.cmp.CmpMessages;
28import org.jboss.as.cmp.context.CmpEntityBeanContext;
29import org.jboss.as.cmp.jdbc.bridge.JDBCCMPFieldBridge;
30import org.jboss.as.cmp.jdbc.bridge.JDBCEntityBridge;
31import org.jboss.as.cmp.jdbc.bridge.JDBCFieldBridge;
32import org.jboss.logging.Logger;
33
34/**
35 * JDBCStoreEntityCommand updates the row with the new state.
36 * In the event that no field is dirty the command just returns.
37 * Note: read-only fields are never considered dirty.
38 *
39 * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
40 * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Oberg</a>
41 * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
42 * @author <a href="mailto:shevlandj@kpi.com.au">Joe Shevland</a>
43 * @author <a href="mailto:justin@j-m-f.demon.co.uk">Justin Forder</a>
44 * @author <a href="mailto:sebastien.alborini@m4x.org">Sebastien Alborini</a>
45 * @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
46 * @version $Revision: 81030 $
47 */
48public final class JDBCStoreEntityCommand {
49 private final JDBCEntityBridge entity;
50 private final JDBCFieldBridge[] primaryKeyFields;
51 private final Logger log;
52
53 public JDBCStoreEntityCommand(JDBCStoreManager manager) {
54 entity = (JDBCEntityBridge) manager.getEntityBridge();
55 primaryKeyFields = entity.getPrimaryKeyFields();
56
57 // Create the Log
58 log = Logger.getLogger(
59 this.getClass().getName() +
60 "." +
61 manager.getMetaData().getName());
62 }
63
64 public void execute(CmpEntityBeanContext ctx) {
65 // scheduled for batch cascade-delete instance should not be updated
66 // because foreign key fields could be updated to null and cascade-delete will fail.
67 JDBCEntityBridge.FieldIterator dirtyIterator = entity.getDirtyIterator(ctx);
68 if (!dirtyIterator.hasNext() || entity.isBeingRemoved(ctx) || entity.isScheduledForBatchCascadeDelete(ctx)) {
69 if (log.isTraceEnabled()) {
70 log.trace("Store command NOT executed. Entity is not dirty "
71 + ", is being removed or scheduled for *batch* cascade delete: pk=" + ctx.getPrimaryKey());
72 }
73 return;
74 }
75
76 // generate sql
77 StringBuffer sql = new StringBuffer(200);
78 sql.append(SQLUtil.UPDATE)
79 .append(entity.getQualifiedTableName())
80 .append(SQLUtil.SET);
81 SQLUtil.getSetClause(dirtyIterator, sql)
82 .append(SQLUtil.WHERE);
83 SQLUtil.getWhereClause(primaryKeyFields, sql);
84
85 boolean hasLockedFields = entity.hasLockedFields(ctx);
86 JDBCEntityBridge.FieldIterator lockedIterator = null;
87 if (hasLockedFields) {
88 lockedIterator = entity.getLockedIterator(ctx);
89 while (lockedIterator.hasNext()) {
90 sql.append(SQLUtil.AND);
91 JDBCCMPFieldBridge field = lockedIterator.next();
92 if (field.getLockedValue(ctx) == null) {
93 SQLUtil.getIsNullClause(false, field, "", sql);
94 lockedIterator.remove();
95 } else {
96 SQLUtil.getWhereClause(field, sql);
97 }
98 }
99 }
100
101 Connection con = null;
102 PreparedStatement ps = null;
103 int rowsAffected = 0;
104 try {
105 // create the statement
106 if (log.isDebugEnabled()) {
107 log.debug("Executing SQL: " + sql);
108 }
109
110 // get the connection
111 con = entity.getDataSource().getConnection();
112 ps = con.prepareStatement(sql.toString());
113
114 // SET: set the dirty fields parameters
115 int index = 1;
116 dirtyIterator.reset();
117 while (dirtyIterator.hasNext()) {
118 index = dirtyIterator.next().setInstanceParameters(ps, index, ctx);
119 }
120
121 // WHERE: set primary key fields
122 index = entity.setPrimaryKeyParameters(ps, index, ctx.getPrimaryKey());
123
124 // WHERE: set optimistically locked field values
125 if (hasLockedFields) {
126 lockedIterator.reset();
127 while (lockedIterator.hasNext()) {
128 JDBCCMPFieldBridge field = lockedIterator.next();
129 Object value = field.getLockedValue(ctx);
130 index = field.setArgumentParameters(ps, index, value);
131 }
132 }
133
134 // execute statement
135 rowsAffected = ps.executeUpdate();
136 } catch (EJBException e) {
137 throw e;
138 } catch (Exception e) {
139 throw CmpMessages.MESSAGES.storeFailed(e);
140 } finally {
141 JDBCUtil.safeClose(ps);
142 JDBCUtil.safeClose(con);
143 }
144
145 // check results
146 if (rowsAffected != 1) {
147 throw CmpMessages.MESSAGES.updateFailedTooManyRowsAffected(rowsAffected, ctx.getPrimaryKey());
148 }
149
150 // Mark the updated fields as clean.
151 dirtyIterator.reset();
152 while (dirtyIterator.hasNext()) {
153 dirtyIterator.next().setClean(ctx);
154 }
155 }
156}