PageRenderTime 50ms CodeModel.GetById 29ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 0ms

/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}