PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/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. */
  22. package org.jboss.as.cmp.jdbc;
  23. import java.lang.reflect.Method;
  24. import java.sql.Connection;
  25. import java.sql.PreparedStatement;
  26. import java.sql.SQLException;
  27. import java.util.ArrayList;
  28. import java.util.Date;
  29. import java.util.List;
  30. import javax.ejb.CreateException;
  31. import org.jboss.as.cmp.CmpMessages;
  32. import static org.jboss.as.cmp.CmpMessages.MESSAGES;
  33. import org.jboss.as.cmp.context.CmpEntityBeanContext;
  34. import org.jboss.as.cmp.jdbc.bridge.JDBCCMPFieldBridge;
  35. import org.jboss.as.cmp.jdbc.bridge.JDBCCMRFieldBridge;
  36. import org.jboss.as.cmp.jdbc.bridge.JDBCEntityBridge;
  37. import org.jboss.as.cmp.jdbc.bridge.JDBCFieldBridge;
  38. import org.jboss.as.cmp.jdbc.metadata.JDBCEntityCommandMetaData;
  39. import org.jboss.logging.Logger;
  40. import org.jboss.security.AuthenticationManager;
  41. /**
  42. * Base class for create commands that drives the operation sequence.
  43. *
  44. * @author <a href="mailto:jeremy@boynes.com">Jeremy Boynes</a>
  45. * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
  46. */
  47. public abstract class JDBCAbstractCreateCommand implements JDBCCreateCommand {
  48. protected Logger log;
  49. protected boolean debug;
  50. protected boolean trace;
  51. protected JDBCEntityBridge entity;
  52. protected AuthenticationManager securityManager;
  53. protected boolean createAllowed;
  54. protected SQLExceptionProcessor exceptionProcessor;
  55. protected String insertSQL;
  56. protected JDBCFieldBridge[] insertFields;
  57. protected boolean insertAfterEjbPostCreate;
  58. // Generated fields
  59. private JDBCCMPFieldBridge createdPrincipal;
  60. private JDBCCMPFieldBridge createdTime;
  61. private JDBCCMPFieldBridge updatedPrincipal;
  62. private JDBCCMPFieldBridge updatedTime;
  63. public void init(JDBCStoreManager manager) {
  64. log = Logger.getLogger(getClass().getName() + '.' + manager.getMetaData().getName());
  65. debug = log.isDebugEnabled();
  66. trace = log.isTraceEnabled();
  67. entity = (JDBCEntityBridge) manager.getEntityBridge();
  68. insertAfterEjbPostCreate = manager.getCmpConfig().isInsertAfterEjbPostCreate();
  69. // set create allowed
  70. createAllowed = true;
  71. JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
  72. for (int i = 0; i < pkFields.length; i++) {
  73. if (pkFields[i].isReadOnly()) {
  74. createAllowed = false;
  75. log.debug("Create will not be allowed because pk field "
  76. + pkFields[i].getFieldName() + "is read only.");
  77. break;
  78. }
  79. }
  80. initGeneratedFields();
  81. JDBCEntityCommandMetaData entityCommand = manager.getMetaData().getEntityCommand();
  82. if (entityCommand == null) {
  83. throw MESSAGES.entityCommandIsNull();
  84. }
  85. initEntityCommand(entityCommand);
  86. initInsertFields();
  87. initInsertSQL();
  88. }
  89. protected void initEntityCommand(JDBCEntityCommandMetaData entityCommand) {
  90. exceptionProcessor = null;
  91. }
  92. public Object execute(Method m, Object[] args, CmpEntityBeanContext ctx) throws CreateException {
  93. // TODO: implement this logic nicer
  94. if (insertAfterEjbPostCreate) {
  95. if (!JDBCEntityBridge.isEjbCreateDone(ctx)) {
  96. checkCreateAllowed();
  97. generateFields(ctx);
  98. JDBCEntityBridge.setEjbCreateDone(ctx);
  99. } else {
  100. beforeInsert(ctx);
  101. performInsert(ctx);
  102. afterInsert(ctx);
  103. JDBCEntityBridge.setCreated(ctx);
  104. }
  105. } else {
  106. checkCreateAllowed();
  107. generateFields(ctx);
  108. beforeInsert(ctx);
  109. performInsert(ctx);
  110. afterInsert(ctx);
  111. JDBCEntityBridge.setCreated(ctx);
  112. }
  113. return getPrimaryKey(ctx);
  114. }
  115. protected void checkCreateAllowed() throws CreateException {
  116. if (!createAllowed) {
  117. throw MESSAGES.creationNotAllowedPKReadOnly();
  118. }
  119. }
  120. protected JDBCCMPFieldBridge getGeneratedPKField() {
  121. // extract the pk field to be generated
  122. JDBCCMPFieldBridge pkField = null;
  123. JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
  124. for (int i = 0; i < pkFields.length; ++i) {
  125. if (pkField != null)
  126. throw MESSAGES.generationOnlySupportedWithSinglePK();
  127. pkField = (JDBCCMPFieldBridge) pkFields[i];
  128. }
  129. return pkField;
  130. }
  131. protected void initGeneratedFields() {
  132. createdPrincipal = entity.getCreatedPrincipalField();
  133. if (securityManager == null && createdPrincipal != null) {
  134. throw MESSAGES.noSecurityDomainForCreatedBy();
  135. }
  136. updatedPrincipal = entity.getUpdatedPrincipalField();
  137. if (securityManager == null && updatedPrincipal != null) {
  138. throw MESSAGES.noSecurityDomainForCreatedBy();
  139. }
  140. createdTime = entity.getCreatedTimeField();
  141. updatedTime = entity.getUpdatedTimeField();
  142. }
  143. protected void generateFields(CmpEntityBeanContext ctx) throws CreateException {
  144. // Audit principal fields
  145. if (securityManager != null) {
  146. String principalName = ctx.getCallerPrincipal().getName();
  147. if (createdPrincipal != null && createdPrincipal.getInstanceValue(ctx) == null) {
  148. createdPrincipal.setInstanceValue(ctx, principalName);
  149. }
  150. /*
  151. if(updatedPrincipal != null && updatedPrincipal.getInstanceValue(ctx) == null)
  152. {
  153. updatedPrincipal.setInstanceValue(ctx, principalName);
  154. }
  155. */
  156. }
  157. // Audit time fields
  158. Date date = null;
  159. if (createdTime != null && createdTime.getInstanceValue(ctx) == null) {
  160. date = new Date();
  161. createdTime.setInstanceValue(ctx, date);
  162. }
  163. /*
  164. if(updatedTime != null && updatedTime.getInstanceValue(ctx) == null)
  165. {
  166. if(date == null)
  167. date = new Date();
  168. updatedTime.setInstanceValue(ctx, date);
  169. }
  170. */
  171. }
  172. protected void initInsertFields() {
  173. JDBCFieldBridge[] fields = entity.getTableFields();
  174. List insertFieldsList = new ArrayList(fields.length);
  175. for (int i = 0; i < fields.length; i++) {
  176. JDBCFieldBridge field = fields[i];
  177. if (isInsertField(field))
  178. insertFieldsList.add(field);
  179. }
  180. insertFields = (JDBCFieldBridge[]) insertFieldsList.toArray(new JDBCFieldBridge[insertFieldsList.size()]);
  181. }
  182. protected boolean isInsertField(JDBCFieldBridge field) {
  183. boolean result =
  184. !(field instanceof JDBCCMRFieldBridge)
  185. && field.getJDBCType() != null
  186. && !field.isReadOnly();
  187. if (field instanceof JDBCCMPFieldBridge)
  188. result = result && !((JDBCCMPFieldBridge) field).isRelationTableField();
  189. return result;
  190. }
  191. protected void initInsertSQL() {
  192. StringBuffer sql = new StringBuffer(250);
  193. sql.append(SQLUtil.INSERT_INTO)
  194. .append(entity.getQualifiedTableName())
  195. .append(" (");
  196. SQLUtil.getColumnNamesClause(insertFields, sql);
  197. sql.append(')')
  198. .append(SQLUtil.VALUES).append('(');
  199. SQLUtil.getValuesClause(insertFields, sql)
  200. .append(')');
  201. insertSQL = sql.toString();
  202. if (debug)
  203. log.debug("Insert Entity SQL: " + insertSQL);
  204. }
  205. protected void beforeInsert(CmpEntityBeanContext ctx) throws CreateException {
  206. }
  207. protected void performInsert(CmpEntityBeanContext ctx) throws CreateException {
  208. Connection c = null;
  209. PreparedStatement ps = null;
  210. boolean throwRuntimeExceptions = entity.getMetaData().getThrowRuntimeExceptions();
  211. // if metadata is true, the getConnection is done inside
  212. // its own try catch block to throw a runtime exception (EJBException)
  213. if (throwRuntimeExceptions) {
  214. try {
  215. c = entity.getDataSource().getConnection();
  216. } catch (SQLException sqle) {
  217. javax.ejb.EJBException ejbe = new javax.ejb.EJBException("Could not get a connection; " + sqle);
  218. ejbe.initCause(sqle);
  219. throw ejbe;
  220. }
  221. }
  222. try {
  223. if (log.isDebugEnabled()) {
  224. log.debug("Executing SQL: " + insertSQL);
  225. }
  226. // if metadata is false, the getConnection is done inside this try catch block
  227. if (!throwRuntimeExceptions) {
  228. c = entity.getDataSource().getConnection();
  229. }
  230. ps = prepareStatement(c, insertSQL, ctx);
  231. // set the parameters
  232. int index = 1;
  233. for (int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd) {
  234. index = insertFields[fieldInd].setInstanceParameters(ps, index, ctx);
  235. }
  236. // execute statement
  237. int rowsAffected = executeInsert(index, ps, ctx);
  238. if (rowsAffected != 1) {
  239. throw CmpMessages.MESSAGES.expectedOneRow(rowsAffected, ctx.getPrimaryKey());
  240. }
  241. } catch (SQLException e) {
  242. if (exceptionProcessor != null && exceptionProcessor.isDuplicateKey(e)) {
  243. throw CmpMessages.MESSAGES.uniqueKeyViolationInvalidFk(ctx.getPrimaryKey());
  244. } else {
  245. throw CmpMessages.MESSAGES.couldNotCreateEntity(e);
  246. }
  247. } finally {
  248. JDBCUtil.safeClose(ps);
  249. JDBCUtil.safeClose(c);
  250. }
  251. // Mark the inserted fields as clean.
  252. for (int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd) {
  253. insertFields[fieldInd].setClean(ctx);
  254. }
  255. }
  256. protected PreparedStatement prepareStatement(Connection c, String sql, CmpEntityBeanContext ctx) throws SQLException {
  257. return c.prepareStatement(sql);
  258. }
  259. protected int executeInsert(int paramIndex, PreparedStatement ps, CmpEntityBeanContext ctx) throws SQLException {
  260. return ps.executeUpdate();
  261. }
  262. protected void afterInsert(CmpEntityBeanContext ctx) throws CreateException {
  263. }
  264. protected Object getPrimaryKey(CmpEntityBeanContext ctx) {
  265. return entity.extractPrimaryKeyFromInstance(ctx);
  266. }
  267. }