KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > JDBCAbstractCreateCommand


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * 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.ejb.plugins.cmp.jdbc;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.sql.Connection JavaDoc;
26 import java.sql.PreparedStatement JavaDoc;
27 import java.sql.SQLException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Date JavaDoc;
30 import java.util.List JavaDoc;
31 import javax.ejb.CreateException JavaDoc;
32 import javax.ejb.FinderException JavaDoc;
33 import javax.management.MalformedObjectNameException JavaDoc;
34 import javax.sql.DataSource JavaDoc;
35
36 import org.jboss.deployment.DeploymentException;
37 import org.jboss.ejb.EntityEnterpriseContext;
38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMPFieldBridge;
39 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCCMRFieldBridge;
40 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge;
41 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
42 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityCommandMetaData;
43 import org.jboss.logging.Logger;
44 import org.jboss.mx.util.MBeanProxyExt;
45 import org.jboss.security.AuthenticationManager;
46
47 /**
48  * Base class for create commands that drives the operation sequence.
49  *
50  * @author <a HREF="mailto:jeremy@boynes.com">Jeremy Boynes</a>
51  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
52  */

53 public abstract class JDBCAbstractCreateCommand implements JDBCCreateCommand
54 {
55    protected Logger log;
56    protected boolean debug;
57    protected boolean trace;
58    protected JDBCEntityBridge entity;
59    protected AuthenticationManager securityManager;
60    protected boolean createAllowed;
61    protected SQLExceptionProcessorMBean exceptionProcessor;
62    protected String JavaDoc insertSQL;
63    protected JDBCFieldBridge[] insertFields;
64    protected boolean insertAfterEjbPostCreate;
65
66    // Generated fields
67
private JDBCCMPFieldBridge createdPrincipal;
68    private JDBCCMPFieldBridge createdTime;
69    private JDBCCMPFieldBridge updatedPrincipal;
70    private JDBCCMPFieldBridge updatedTime;
71
72    public void init(JDBCStoreManager manager) throws DeploymentException
73    {
74       log = Logger.getLogger(getClass().getName() + '.' + manager.getMetaData().getName());
75       debug = log.isDebugEnabled();
76       trace = log.isTraceEnabled();
77
78       entity = (JDBCEntityBridge) manager.getEntityBridge();
79       securityManager = manager.getContainer().getSecurityManager();
80
81       insertAfterEjbPostCreate = manager.getContainer()
82          .getBeanMetaData().getContainerConfiguration().isInsertAfterEjbPostCreate();
83
84       // set create allowed
85
createAllowed = true;
86       JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
87       for(int i = 0; i < pkFields.length; i++)
88       {
89          if(pkFields[i].isReadOnly())
90          {
91             createAllowed = false;
92             log.debug("Create will not be allowed because pk field "
93                + pkFields[i].getFieldName() + "is read only.");
94             break;
95          }
96       }
97
98       initGeneratedFields();
99
100       JDBCEntityCommandMetaData entityCommand = manager.getMetaData().getEntityCommand();
101       if(entityCommand == null)
102       {
103          throw new DeploymentException("entity-command is null");
104       }
105       initEntityCommand(entityCommand);
106
107       initInsertFields();
108       initInsertSQL();
109    }
110
111    protected void initEntityCommand(JDBCEntityCommandMetaData entityCommand) throws DeploymentException
112    {
113       String JavaDoc objectName = entityCommand.getAttribute("SQLExceptionProcessor");
114       if(objectName != null)
115       {
116          try
117          {
118             exceptionProcessor = (SQLExceptionProcessorMBean) MBeanProxyExt.create(SQLExceptionProcessorMBean.class, objectName);
119          }
120          catch(MalformedObjectNameException JavaDoc e)
121          {
122             throw new DeploymentException("Invalid object name for SQLExceptionProcessor: ", e);
123          }
124       }
125    }
126
127    public Object JavaDoc execute(Method JavaDoc m, Object JavaDoc[] args, EntityEnterpriseContext ctx) throws CreateException JavaDoc
128    {
129       // TODO: implement this logic nicer
130
if(insertAfterEjbPostCreate)
131       {
132          if(!JDBCEntityBridge.isEjbCreateDone(ctx))
133          {
134             checkCreateAllowed();
135             generateFields(ctx);
136             JDBCEntityBridge.setEjbCreateDone(ctx);
137          }
138          else
139          {
140             beforeInsert(ctx);
141             performInsert(ctx);
142             afterInsert(ctx);
143             JDBCEntityBridge.setCreated(ctx);
144          }
145       }
146       else
147       {
148          checkCreateAllowed();
149          generateFields(ctx);
150          beforeInsert(ctx);
151          performInsert(ctx);
152          afterInsert(ctx);
153          JDBCEntityBridge.setCreated(ctx);
154       }
155       return getPrimaryKey(ctx);
156    }
157
158    protected void checkCreateAllowed() throws CreateException JavaDoc
159    {
160       if(!createAllowed)
161       {
162          throw new CreateException JavaDoc("Creation is not allowed because a primary key field is read only.");
163       }
164    }
165
166    protected JDBCCMPFieldBridge getGeneratedPKField() throws DeploymentException
167    {
168       // extract the pk field to be generated
169
JDBCCMPFieldBridge pkField = null;
170       JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
171       for(int i = 0; i < pkFields.length; ++i)
172       {
173          if(pkField != null)
174             throw new DeploymentException("Generation only supported with single PK field");
175          pkField = (JDBCCMPFieldBridge)pkFields[i];
176       }
177       return pkField;
178    }
179
180    protected void initGeneratedFields() throws DeploymentException
181    {
182       createdPrincipal = entity.getCreatedPrincipalField();
183       if(securityManager == null && createdPrincipal != null)
184       {
185          throw new DeploymentException("No security-domain configured but created-by specified");
186       }
187       updatedPrincipal = entity.getUpdatedPrincipalField();
188       if(securityManager == null && updatedPrincipal != null)
189       {
190          throw new DeploymentException("No security-domain configured but updated-by specified");
191       }
192       createdTime = entity.getCreatedTimeField();
193       updatedTime = entity.getUpdatedTimeField();
194    }
195
196    protected void generateFields(EntityEnterpriseContext ctx) throws CreateException JavaDoc
197    {
198       // Audit principal fields
199
if(securityManager != null)
200       {
201          String JavaDoc principalName = ctx.getEJBContext().getCallerPrincipal().getName();
202          if(createdPrincipal != null && createdPrincipal.getInstanceValue(ctx) == null)
203          {
204             createdPrincipal.setInstanceValue(ctx, principalName);
205          }
206          /*
207          if(updatedPrincipal != null && updatedPrincipal.getInstanceValue(ctx) == null)
208          {
209             updatedPrincipal.setInstanceValue(ctx, principalName);
210          }
211          */

212       }
213
214       // Audit time fields
215
Date JavaDoc date = null;
216       if(createdTime != null && createdTime.getInstanceValue(ctx) == null)
217       {
218          date = new Date JavaDoc();
219          createdTime.setInstanceValue(ctx, date);
220       }
221       /*
222       if(updatedTime != null && updatedTime.getInstanceValue(ctx) == null)
223       {
224          if(date == null)
225             date = new Date();
226          updatedTime.setInstanceValue(ctx, date);
227       }
228       */

229    }
230
231    protected void initInsertFields()
232    {
233       JDBCFieldBridge[] fields = entity.getTableFields();
234       List JavaDoc insertFieldsList = new ArrayList JavaDoc(fields.length);
235       for(int i = 0; i < fields.length; i++)
236       {
237          JDBCFieldBridge field = fields[i];
238          if(isInsertField(field))
239             insertFieldsList.add(field);
240       }
241
242       insertFields = (JDBCFieldBridge[]) insertFieldsList.toArray(new JDBCFieldBridge[insertFieldsList.size()]);
243    }
244
245    protected boolean isInsertField(JDBCFieldBridge field)
246    {
247       boolean result =
248          !(field instanceof JDBCCMRFieldBridge)
249          && field.getJDBCType() != null
250          && !field.isReadOnly();
251       if(field instanceof JDBCCMPFieldBridge)
252          result = result && !((JDBCCMPFieldBridge) field).isRelationTableField();
253       return result;
254    }
255
256    protected void initInsertSQL()
257    {
258       StringBuffer JavaDoc sql = new StringBuffer JavaDoc(250);
259       sql.append(SQLUtil.INSERT_INTO)
260          .append(entity.getQualifiedTableName())
261          .append(" (");
262
263       SQLUtil.getColumnNamesClause(insertFields, sql);
264
265       sql.append(')')
266          .append(SQLUtil.VALUES).append('(');
267       SQLUtil.getValuesClause(insertFields, sql)
268          .append(')');
269       insertSQL = sql.toString();
270
271       if(debug)
272          log.debug("Insert Entity SQL: " + insertSQL);
273    }
274
275    protected void beforeInsert(EntityEnterpriseContext ctx) throws CreateException JavaDoc
276    {
277    }
278
279    protected void performInsert(EntityEnterpriseContext ctx) throws CreateException JavaDoc
280    {
281       Connection JavaDoc c = null;
282       PreparedStatement JavaDoc ps = null;
283       boolean throwRuntimeExceptions = entity.getMetaData().getThrowRuntimeExceptions();
284
285       // if metadata is true, the getconnection is done inside
286
// its own try catch block to throw a runtime exception (EJBException)
287
if (throwRuntimeExceptions)
288       {
289           try
290           {
291               c = entity.getDataSource().getConnection();
292           }
293           catch (SQLException JavaDoc sqle)
294           {
295               javax.ejb.EJBException JavaDoc ejbe = new javax.ejb.EJBException JavaDoc("Could not get a connection; " + sqle);
296               ejbe.initCause(sqle);
297               throw ejbe;
298           }
299       }
300      
301       try
302       {
303          if(debug)
304             log.debug("Executing SQL: " + insertSQL);
305
306
307          // if metadata is false, the getconnection is done inside this try catch block
308
if ( ! throwRuntimeExceptions)
309          {
310              c = entity.getDataSource().getConnection();
311          }
312          ps = prepareStatement(c, insertSQL, ctx);
313
314          // set the parameters
315
int index = 1;
316          for(int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd)
317          {
318             index = insertFields[fieldInd].setInstanceParameters(ps, index, ctx);
319          }
320
321          // execute statement
322
int rowsAffected = executeInsert(index, ps, ctx);
323          if(rowsAffected != 1)
324          {
325             throw new CreateException JavaDoc("Expected one affected row but update returned" + rowsAffected +
326                " for id=" + ctx.getId());
327          }
328       }
329       catch(SQLException JavaDoc e)
330       {
331          if(exceptionProcessor != null && exceptionProcessor.isDuplicateKey(e))
332          {
333             log.error("Failed to create instance.", e);
334             throw new CreateException JavaDoc(
335                "Integrity constraint violation. Possibly unique key violation or invalid foreign key value."
336             );
337          }
338          else
339          {
340             log.error("Could not create entity", e);
341             CreateException JavaDoc ce = new CreateException JavaDoc("Could not create entity: " + e);
342             ce.initCause(e);
343             throw ce;
344          }
345       }
346       finally
347       {
348          JDBCUtil.safeClose(ps);
349          JDBCUtil.safeClose(c);
350       }
351
352       // Mark the inserted fields as clean.
353
for(int fieldInd = 0; fieldInd < insertFields.length; ++fieldInd)
354       {
355          insertFields[fieldInd].setClean(ctx);
356       }
357    }
358
359    protected PreparedStatement JavaDoc prepareStatement(Connection JavaDoc c, String JavaDoc sql, EntityEnterpriseContext ctx) throws SQLException JavaDoc
360    {
361       return c.prepareStatement(sql);
362    }
363
364    protected int executeInsert(int paramIndex, PreparedStatement JavaDoc ps, EntityEnterpriseContext ctx) throws SQLException JavaDoc
365    {
366       return ps.executeUpdate();
367    }
368
369    protected void afterInsert(EntityEnterpriseContext ctx) throws CreateException JavaDoc
370    {
371    }
372
373    protected Object JavaDoc getPrimaryKey(EntityEnterpriseContext ctx)
374    {
375       return entity.extractPrimaryKeyFromInstance(ctx);
376    }
377 }
378
Popular Tags