KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > bridge > JDBCEntityBridge


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.bridge;
23
24 import java.sql.PreparedStatement JavaDoc;
25 import java.sql.ResultSet JavaDoc;
26
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collection JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Arrays JavaDoc;
35 import java.util.NoSuchElementException JavaDoc;
36 import java.rmi.RemoteException JavaDoc;
37
38 import javax.ejb.EJBException JavaDoc;
39 import javax.ejb.RemoveException JavaDoc;
40 import javax.sql.DataSource JavaDoc;
41 import javax.naming.InitialContext JavaDoc;
42 import javax.naming.NamingException JavaDoc;
43
44 import org.jboss.deployment.DeploymentException;
45 import org.jboss.ejb.EntityEnterpriseContext;
46
47 import org.jboss.ejb.plugins.cmp.jdbc.JDBCContext;
48 import org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager;
49 import org.jboss.ejb.plugins.cmp.jdbc.SQLUtil;
50 import org.jboss.ejb.plugins.cmp.jdbc.LockingStrategy;
51 import org.jboss.ejb.plugins.cmp.jdbc.JDBCTypeFactory;
52 import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
53
54 import org.jboss.ejb.plugins.cmp.bridge.EntityBridgeInvocationHandler;
55 import org.jboss.ejb.plugins.cmp.bridge.FieldBridge;
56
57 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCAuditMetaData;
58 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
59 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
60 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData;
61 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData;
62 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCOptimisticLockingMetaData;
63 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
64 import org.jboss.proxy.compiler.Proxies;
65 import org.jboss.proxy.compiler.InvocationHandler;
66 import org.jboss.logging.Logger;
67
68
69 /**
70  * JDBCEntityBridge follows the Bridge pattern [Gamma et. al, 1995].
71  * The main job of this class is to construct the bridge from entity meta data.
72  *
73  * Life-cycle:
74  * Undefined. Should be tied to CMPStoreManager.
75  *
76  * Multiplicity:
77  * One per cmp entity bean type.
78  *
79  * @author <a HREF="mailto:dain@daingroup.com">Dain Sundstrom</a>
80  * @author <a HREF="mailto:loubyansky@ua.fm">Alex Loubyansky</a>
81  * @author <a HREF="mailto:heiko.rupp@cellent.de">Heiko W. Rupp</a>
82  * @version $Revision: 43495 $
83  */

84 public class JDBCEntityBridge implements JDBCAbstractEntityBridge
85 {
86    public final static byte LOADED = 1;
87    public final static byte LOAD_REQUIRED = 2;
88    public final static byte DIRTY = 4;
89    public final static byte CHECK_DIRTY = 8;
90    public final static byte LOCKED = 16;
91    public final static byte ADD_TO_SET_ON_UPDATE = 32;
92    public final static byte ADD_TO_WHERE_ON_UPDATE = 64;
93
94    private static final String JavaDoc DEFAULT_LOADGROUP_NAME = "*";
95
96    private JDBCEntityMetaData metadata;
97    private JDBCStoreManager manager;
98    private DataSource JavaDoc dataSource;
99    private String JavaDoc qualifiedTableName;
100    private String JavaDoc tableName;
101
102    /** primary key fields (not added to cmpFields) */
103    private final String JavaDoc primaryKeyFieldName;
104    private final Class JavaDoc primaryKeyClass;
105    private JDBCCMPFieldBridge[] primaryKeyFields;
106    /** CMP fields */
107    private JDBCCMPFieldBridge[] cmpFields;
108    /** CMR fields */
109    private JDBCCMRFieldBridge[] cmrFields;
110    /** table fields */
111    private JDBCCMPFieldBridge[] tableFields;
112
113    /** used for optimistic locking. (added to cmpFields) */
114    private JDBCCMPFieldBridge versionField;
115
116    // Audit fields (added to cmpFields)
117
private JDBCCMPFieldBridge createdPrincipalField;
118    private JDBCCMPFieldBridge createdTimeField;
119    private JDBCCMPFieldBridge updatedPrincipalField;
120    private JDBCCMPFieldBridge updatedTimeField;
121
122    private Map JavaDoc selectorsByMethod;
123
124    /** Load group is a boolean array with tableFields.length elements. True means the element is in the group. */
125    private Map JavaDoc loadGroupMasks;
126    private List JavaDoc lazyLoadGroupMasks;
127    private boolean[] eagerLoadGroupMask;
128    private boolean[] defaultLockGroupMask;
129
130    private int jdbcContextSize;
131
132    private final Logger log;
133
134    public JDBCEntityBridge(JDBCEntityMetaData metadata, JDBCStoreManager manager)
135       throws DeploymentException
136    {
137       this.metadata = metadata;
138       this.manager = manager;
139       primaryKeyFieldName = metadata.getPrimaryKeyFieldName();
140       primaryKeyClass = metadata.getPrimaryKeyClass();
141       log = Logger.getLogger(this.getClass().getName() + "." + metadata.getName());
142    }
143
144    public void init() throws DeploymentException
145    {
146       try
147       {
148          InitialContext JavaDoc ic = new InitialContext JavaDoc();
149          dataSource = (DataSource JavaDoc)ic.lookup(metadata.getDataSourceName());
150       }
151       catch(NamingException JavaDoc e)
152       {
153          throw new DeploymentException("Error: can't find data source: " +
154             metadata.getDataSourceName(), e);
155       }
156
157       qualifiedTableName = SQLUtil.fixTableName(metadata.getDefaultTableName(), dataSource);
158       int dotIndex = qualifiedTableName.indexOf('.');
159       tableName = dotIndex == -1 ? qualifiedTableName : qualifiedTableName.substring(dotIndex + 1);
160
161       // CMP fields
162
loadCMPFields(metadata);
163
164       // CMR fields
165
loadCMRFields(metadata);
166
167       // create locking field
168
JDBCOptimisticLockingMetaData lockMetaData = metadata.getOptimisticLocking();
169       if(lockMetaData != null && lockMetaData.getLockingField() != null)
170       {
171          Integer JavaDoc strategy = lockMetaData.getLockingStrategy();
172          JDBCCMPFieldMetaData versionMD = lockMetaData.getLockingField();
173
174          versionField = getCMPFieldByName(versionMD.getFieldName());
175          boolean hidden = versionField == null;
176          if(strategy == JDBCOptimisticLockingMetaData.VERSION_COLUMN_STRATEGY)
177          {
178             if(hidden)
179                versionField = new JDBCLongVersionFieldBridge(manager, versionMD);
180             else
181                versionField = new JDBCLongVersionFieldBridge((JDBCCMP2xFieldBridge)versionField);
182          }
183          else if(strategy == JDBCOptimisticLockingMetaData.TIMESTAMP_COLUMN_STRATEGY)
184          {
185             if(hidden)
186                versionField = new JDBCTimestampVersionFieldBridge(manager, versionMD);
187             else
188                versionField = new JDBCTimestampVersionFieldBridge((JDBCCMP2xFieldBridge)versionField);
189          }
190          else if(strategy == JDBCOptimisticLockingMetaData.KEYGENERATOR_COLUMN_STRATEGY)
191          {
192             if(hidden)
193                versionField = new JDBCKeyGenVersionFieldBridge(
194                   manager, versionMD, lockMetaData.getKeyGeneratorFactory());
195             else
196                versionField = new JDBCKeyGenVersionFieldBridge(
197                   (JDBCCMP2xFieldBridge)versionField, lockMetaData.getKeyGeneratorFactory());
198          }
199
200          if(hidden)
201             addCMPField(versionField);
202          else
203             tableFields[versionField.getTableIndex()] = versionField;
204       }
205
206       // audit fields
207
JDBCAuditMetaData auditMetaData = metadata.getAudit();
208       if(auditMetaData != null)
209       {
210          JDBCCMPFieldMetaData auditField = auditMetaData.getCreatedPrincipalField();
211          if(auditField != null)
212          {
213             createdPrincipalField = getCMPFieldByName(auditField.getFieldName());
214             if(createdPrincipalField == null)
215             {
216                createdPrincipalField = new JDBCCMP2xFieldBridge(manager, auditField);
217                addCMPField(createdPrincipalField);
218             }
219          }
220          else
221          {
222             createdPrincipalField = null;
223          }
224
225          auditField = auditMetaData.getCreatedTimeField();
226          if(auditField != null)
227          {
228             createdTimeField = getCMPFieldByName(auditField.getFieldName());
229             if(createdTimeField == null)
230             {
231                createdTimeField = new JDBCCMP2xFieldBridge(manager, auditField, JDBCTypeFactory.EQUALS, false);
232                addCMPField(createdTimeField);
233             }
234             else
235             {
236                // just to override state factory and check-dirty-after-get
237
createdTimeField = new JDBCCMP2xFieldBridge(
238                   (JDBCCMP2xFieldBridge)createdTimeField, JDBCTypeFactory.EQUALS, false);
239                tableFields[createdTimeField.getTableIndex()] = createdTimeField;
240             }
241          }
242          else
243          {
244             createdTimeField = null;
245          }
246
247          auditField = auditMetaData.getUpdatedPrincipalField();
248          if(auditField != null)
249          {
250             updatedPrincipalField = getCMPFieldByName(auditField.getFieldName());
251             if(updatedPrincipalField == null)
252             {
253                updatedPrincipalField = new JDBCCMP2xUpdatedPrincipalFieldBridge(manager, auditField);
254                addCMPField(updatedPrincipalField);
255             }
256             else
257             {
258                updatedPrincipalField = new JDBCCMP2xUpdatedPrincipalFieldBridge(
259                   (JDBCCMP2xFieldBridge)updatedPrincipalField);
260                tableFields[updatedPrincipalField.getTableIndex()] = updatedPrincipalField;
261             }
262          }
263          else
264          {
265             updatedPrincipalField = null;
266          }
267
268          auditField = auditMetaData.getUpdatedTimeField();
269          if(auditField != null)
270          {
271             updatedTimeField = getCMPFieldByName(auditField.getFieldName());
272             if(updatedTimeField == null)
273             {
274                updatedTimeField = new JDBCCMP2xUpdatedTimeFieldBridge(manager, auditField);
275                addCMPField(updatedTimeField);
276             }
277             else
278             {
279                updatedTimeField = new JDBCCMP2xUpdatedTimeFieldBridge((JDBCCMP2xFieldBridge)updatedTimeField);
280                tableFields[updatedTimeField.getTableIndex()] = updatedTimeField;
281             }
282          }
283          else
284          {
285             updatedTimeField = null;
286          }
287       }
288
289       // ejbSelect methods
290
loadSelectors(metadata);
291    }
292
293    public void resolveRelationships() throws DeploymentException
294    {
295       for(int i = 0; i < cmrFields.length; ++i)
296          cmrFields[i].resolveRelationship();
297
298       // load groups: cannot be created until relationships have
299
// been resolved because loadgroups must check for foreign keys
300
loadLoadGroups(metadata);
301       loadEagerLoadGroup(metadata);
302       loadLazyLoadGroups(metadata);
303    }
304
305    /**
306     * The third phase of deployment. The method is called when relationships are already resolved.
307     * @throws DeploymentException
308     */

309    public void start() throws DeploymentException
310    {
311       for(int i = 0; i < cmrFields.length; ++i)
312       {
313          cmrFields[i].start();
314       }
315    }
316
317    public boolean removeFromRelations(EntityEnterpriseContext ctx, Object JavaDoc[] oldRelations)
318    {
319       boolean removed = false;
320       for(int i = 0; i < cmrFields.length; ++i)
321       {
322          if(cmrFields[i].removeFromRelations(ctx, oldRelations))
323             removed = true;
324       }
325       return removed;
326    }
327
328    public void cascadeDelete(EntityEnterpriseContext ctx, Map JavaDoc oldRelations)
329       throws RemoveException JavaDoc, RemoteException JavaDoc
330    {
331       for(int i = 0; i < cmrFields.length; ++i)
332       {
333          JDBCCMRFieldBridge cmrField = cmrFields[i];
334          Object JavaDoc value = oldRelations.get(cmrField);
335          if(value != null)
336             cmrField.cascadeDelete(ctx, (List JavaDoc)value);
337       }
338    }
339
340    public String JavaDoc getEntityName()
341    {
342       return metadata.getName();
343    }
344
345    public String JavaDoc getAbstractSchemaName()
346    {
347       return metadata.getAbstractSchemaName();
348    }
349
350    public Class JavaDoc getRemoteInterface()
351    {
352       return metadata.getRemoteClass();
353    }
354
355    public Class JavaDoc getLocalInterface()
356    {
357       return metadata.getLocalClass();
358    }
359
360    public JDBCEntityMetaData getMetaData()
361    {
362       return metadata;
363    }
364
365    public JDBCEntityPersistenceStore getManager()
366    {
367       return manager;
368    }
369
370    /**
371     * Returns the datasource for this entity.
372     */

373    public DataSource JavaDoc getDataSource()
374    {
375       return dataSource;
376    }
377
378    public String JavaDoc getTableName()
379    {
380       return tableName;
381    }
382
383    public String JavaDoc getQualifiedTableName()
384    {
385       return qualifiedTableName;
386    }
387
388    public Class JavaDoc getPrimaryKeyClass()
389    {
390       return primaryKeyClass;
391    }
392
393    public int getListCacheMax()
394    {
395       return metadata.getListCacheMax();
396    }
397
398    public int getFetchSize()
399    {
400       return metadata.getFetchSize();
401    }
402
403    public Object JavaDoc createPrimaryKeyInstance()
404    {
405       if(primaryKeyFieldName == null)
406       {
407          try
408          {
409             return primaryKeyClass.newInstance();
410          }
411          catch(Exception JavaDoc e)
412          {
413             throw new EJBException JavaDoc("Error creating primary key instance: ", e);
414          }
415       }
416       return null;
417    }
418
419    public JDBCFieldBridge[] getPrimaryKeyFields()
420    {
421       return primaryKeyFields;
422    }
423
424    /**
425     * This method is called only at deployment time, not called at runtime.
426     * @return the list of all the fields.
427     */

428    public List JavaDoc getFields()
429    {
430       int fieldsTotal = primaryKeyFields.length + cmpFields.length + cmrFields.length;
431       JDBCFieldBridge[] fields = new JDBCFieldBridge[fieldsTotal];
432       int position = 0;
433       // primary key fields
434
System.arraycopy(primaryKeyFields, 0, fields, position, primaryKeyFields.length);
435       position += primaryKeyFields.length;
436       // cmp fields
437
System.arraycopy(cmpFields, 0, fields, position, cmpFields.length);
438       position += cmpFields.length;
439       // cmr fields
440
System.arraycopy(cmrFields, 0, fields, position, cmrFields.length);
441       return Arrays.asList(fields);
442    }
443
444    public FieldBridge getFieldByName(String JavaDoc name)
445    {
446       FieldBridge field = null;
447       for(int i = 0; i < primaryKeyFields.length; ++i)
448       {
449          JDBCCMPFieldBridge primaryKeyField = primaryKeyFields[i];
450          if(primaryKeyField.getFieldName().equals(name))
451          {
452             field = primaryKeyField;
453             break;
454          }
455       }
456       if(field == null)
457       {
458          field = getCMPFieldByName(name);
459       }
460       if(field == null)
461       {
462          field = getCMRFieldByName(name);
463       }
464       return field;
465    }
466
467    public boolean[] getEagerLoadMask()
468    {
469       return eagerLoadGroupMask;
470    }
471
472    public Iterator JavaDoc getLazyLoadGroupMasks()
473    {
474       return lazyLoadGroupMasks.iterator();
475    }
476
477    public boolean[] getLoadGroupMask(String JavaDoc name)
478    {
479       boolean[] mask = (boolean[])loadGroupMasks.get(name);
480       if(mask == null)
481       {
482          throw new IllegalStateException JavaDoc(
483             "Load group '" + name + "' is not defined. Defined load groups: " + loadGroupMasks.keySet()
484          );
485       }
486       return mask;
487    }
488
489    public FieldIterator getLoadIterator(JDBCCMPFieldBridge requiredField,
490                                         JDBCReadAheadMetaData readahead,
491                                         EntityEnterpriseContext ctx)
492    {
493       boolean[] loadGroup;
494       if(requiredField == null)
495       {
496          if(readahead != null && !readahead.isNone())
497          {
498             if(log.isTraceEnabled())
499             {
500                log.trace("Eager-load for entity: readahead=" + readahead);
501             }
502             loadGroup = getLoadGroupMask(readahead.getEagerLoadGroup());
503          }
504          else
505          {
506             if(log.isTraceEnabled())
507             {
508                log.trace("Default eager-load for entity: readahead=" + readahead);
509             }
510             loadGroup = eagerLoadGroupMask;
511          }
512       }
513       else
514       {
515          loadGroup = new boolean[tableFields.length];
516          int requiredInd = requiredField.getTableIndex();
517          loadGroup[requiredInd] = true;
518          for(Iterator JavaDoc groups = lazyLoadGroupMasks.iterator(); groups.hasNext();)
519          {
520             boolean[] lazyGroup = (boolean[])groups.next();
521             if(lazyGroup[requiredInd])
522             {
523                for(int i = 0; i < loadGroup.length; ++i)
524                   loadGroup[i] = loadGroup[i] || lazyGroup[i];
525             }
526          }
527       }
528
529       FieldIterator loadIter;
530       if(loadGroup != null)
531       {
532          // filter
533
int fieldsToLoad = 0;
534          EntityState entityState = getEntityState(ctx);
535          for(int i = 0; i < tableFields.length; ++i)
536          {
537             JDBCCMPFieldBridge field = tableFields[i];
538             if(loadGroup[i] && !field.isPrimaryKeyMember() && !field.isLoaded(ctx))
539             {
540                entityState.setLoadRequired(i);
541                ++fieldsToLoad;
542             }
543          }
544          loadIter = (fieldsToLoad > 0 ? entityState.getLoadIterator(ctx) : EMPTY_FIELD_ITERATOR);
545       }
546       else
547       {
548          loadIter = EMPTY_FIELD_ITERATOR;
549       }
550       return loadIter;
551    }
552
553    /**
554     * @param name CMP field name
555     * @return JDBCCMPFieldBridge instance or null if no field found.
556     */

557    public JDBCCMPFieldBridge getCMPFieldByName(String JavaDoc name)
558    {
559       for(int i = 0; i < primaryKeyFields.length; ++i)
560       {
561          JDBCCMPFieldBridge cmpField = primaryKeyFields[i];
562          if(cmpField.getFieldName().equals(name))
563             return cmpField;
564       }
565       for(int i = 0; i < cmpFields.length; ++i)
566       {
567          JDBCCMPFieldBridge cmpField = cmpFields[i];
568          if(cmpField.getFieldName().equals(name))
569             return cmpField;
570       }
571       return null;
572    }
573
574    public JDBCAbstractCMRFieldBridge[] getCMRFields()
575    {
576       return cmrFields;
577    }
578
579    public JDBCCMRFieldBridge getCMRFieldByName(String JavaDoc name)
580    {
581       for(int i = 0; i < cmrFields.length; ++i)
582       {
583          JDBCCMRFieldBridge cmrField = cmrFields[i];
584          if(cmrField.getFieldName().equals(name))
585             return cmrField;
586       }
587       return null;
588    }
589
590    public JDBCCMPFieldBridge getVersionField()
591    {
592       return versionField;
593    }
594
595    public JDBCCMPFieldBridge getCreatedPrincipalField()
596    {
597       return createdPrincipalField;
598    }
599
600    public JDBCCMPFieldBridge getCreatedTimeField()
601    {
602       return createdTimeField;
603    }
604
605    public JDBCCMPFieldBridge getUpdatedPrincipalField()
606    {
607       return updatedPrincipalField;
608    }
609
610    public JDBCCMPFieldBridge getUpdatedTimeField()
611    {
612       return updatedTimeField;
613    }
614
615    public Collection JavaDoc getSelectors()
616    {
617       return selectorsByMethod.values();
618    }
619
620    public void initInstance(EntityEnterpriseContext ctx)
621    {
622       for(int i = 0; i < tableFields.length; ++i)
623          tableFields[i].initInstance(ctx);
624       //for(int i = 0; i < primaryKeyFields.length; ++i)
625
// primaryKeyFields[i].initInstance(ctx);
626
//for(int i = 0; i < cmpFields.length; ++i)
627
// cmpFields[i].initInstance(ctx);
628
for(int i = 0; i < cmrFields.length; ++i)
629       {
630          JDBCCMRFieldBridge cmrField = cmrFields[i];
631          cmrField.initInstance(ctx);
632       }
633    }
634
635    public static boolean isEjbCreateDone(EntityEnterpriseContext ctx)
636    {
637       return getEntityState(ctx).ejbCreateDone;
638    }
639
640    public static void setCreated(EntityEnterpriseContext ctx)
641    {
642       getEntityState(ctx).setCreated();
643    }
644
645    public static void setEjbCreateDone(EntityEnterpriseContext ctx)
646    {
647       getEntityState(ctx).ejbCreateDone = true;
648    }
649
650    /**
651     * This method is used to determined whether the instance was modified.
652     * NOTE, even if the method returns true the isStoreRequired for this same instance
653     * might return false, e.g. a CMR field that doesn't have a foreign key was modified.
654     * @param ctx
655     * @return
656     */

657    public boolean isModified(EntityEnterpriseContext ctx)
658    {
659       boolean invalidateCache = false;
660       final EntityState entityState = getEntityState(ctx);
661       if(entityState.isCreated())
662       {
663          invalidateCache = areCmpFieldsDirty(ctx, entityState);
664          if(!invalidateCache)
665          {
666             for(int i = 0; i < cmrFields.length; ++i)
667             {
668                if(cmrFields[i].invalidateCache(ctx))
669                {
670                   invalidateCache = true;
671                   break;
672                }
673             }
674          }
675       }
676       return invalidateCache;
677    }
678
679    public boolean isStoreRequired(EntityEnterpriseContext ctx)
680    {
681       boolean modified = false;
682       final EntityState entityState = getEntityState(ctx);
683       if(entityState.isCreated())
684       {
685          modified = areCmpFieldsDirty(ctx, entityState);
686          if(!modified)
687          {
688             for(int i = 0; i < cmrFields.length; ++i)
689             {
690                if(cmrFields[i].isDirty(ctx))
691                {
692                   modified = true;
693                   break;
694                }
695             }
696          }
697       }
698       return modified;
699    }
700
701    private boolean areCmpFieldsDirty(final EntityEnterpriseContext ctx,
702                                      final EntityState entityState)
703    {
704       for(int i = 0; i < tableFields.length; ++i)
705       {
706          final JDBCCMPFieldBridge field = tableFields[i];
707          if(entityState.isCheckDirty(i) && field.isDirty(ctx))
708          {
709             return true;
710          }
711       }
712       return false;
713    }
714
715    public FieldIterator getDirtyIterator(EntityEnterpriseContext ctx)
716    {
717       int dirtyFields = 0;
718       final EntityState entityState = getEntityState(ctx);
719       for(int i = 0; i < tableFields.length; ++i)
720       {
721          JDBCCMPFieldBridge field = tableFields[i];
722          if(entityState.isCheckDirty(i) && field.isDirty(ctx))
723          {
724             entityState.setUpdateRequired(i);
725             ++dirtyFields;
726          }
727       }
728
729       return dirtyFields > 0 ? getEntityState(ctx).getDirtyIterator(ctx) : EMPTY_FIELD_ITERATOR;
730    }
731
732    public boolean hasLockedFields(EntityEnterpriseContext ctx)
733    {
734       return getEntityState(ctx).hasLockedFields();
735    }
736
737    public FieldIterator getLockedIterator(EntityEnterpriseContext ctx)
738    {
739       return getEntityState(ctx).getLockedIterator(ctx);
740    }
741
742    public void initPersistenceContext(EntityEnterpriseContext ctx)
743    {
744       // If we have an EJB 2.0 dynaymic proxy,
745
// notify the handler of the assigned context.
746
Object JavaDoc instance = ctx.getInstance();
747       if(instance instanceof Proxies.ProxyTarget)
748       {
749          InvocationHandler handler = ((Proxies.ProxyTarget)instance).getInvocationHandler();
750          if(handler instanceof EntityBridgeInvocationHandler)
751             ((EntityBridgeInvocationHandler)handler).setContext(ctx);
752       }
753       ctx.setPersistenceContext(new JDBCContext(jdbcContextSize, new EntityState()));
754    }
755
756    /**
757     * This is only called in commit option B
758     */

759    public void resetPersistenceContext(EntityEnterpriseContext ctx)
760    {
761       for(int i = 0; i < primaryKeyFields.length; ++i)
762          primaryKeyFields[i].resetPersistenceContext(ctx);
763       for(int i = 0; i < cmpFields.length; ++i)
764          cmpFields[i].resetPersistenceContext(ctx);
765       for(int i = 0; i < cmrFields.length; ++i)
766          cmrFields[i].resetPersistenceContext(ctx);
767    }
768
769
770    public static void destroyPersistenceContext(EntityEnterpriseContext ctx)
771    {
772       // If we have an EJB 2.0 dynaymic proxy,
773
// notify the handler of the assigned context.
774
Object JavaDoc instance = ctx.getInstance();
775       if(instance instanceof Proxies.ProxyTarget)
776       {
777          InvocationHandler handler = ((Proxies.ProxyTarget)instance).getInvocationHandler();
778          if(handler instanceof EntityBridgeInvocationHandler)
779             ((EntityBridgeInvocationHandler)handler).setContext(null);
780       }
781       ctx.setPersistenceContext(null);
782    }
783
784    //
785
// Commands to handle primary keys
786
//
787

788    public int setPrimaryKeyParameters(PreparedStatement JavaDoc ps, int parameterIndex, Object JavaDoc primaryKey)
789    {
790       for(int i = 0; i < primaryKeyFields.length; ++i)
791          parameterIndex = primaryKeyFields[i].setPrimaryKeyParameters(ps, parameterIndex, primaryKey);
792       return parameterIndex;
793    }
794
795    public int loadPrimaryKeyResults(ResultSet JavaDoc rs, int parameterIndex, Object JavaDoc[] pkRef)
796    {
797       pkRef[0] = createPrimaryKeyInstance();
798       for(int i = 0; i < primaryKeyFields.length; ++i)
799          parameterIndex = primaryKeyFields[i].loadPrimaryKeyResults(rs, parameterIndex, pkRef);
800       return parameterIndex;
801    }
802
803    public Object JavaDoc extractPrimaryKeyFromInstance(EntityEnterpriseContext ctx)
804    {
805       try
806       {
807          Object JavaDoc pk = null;
808          for(int i = 0; i < primaryKeyFields.length; ++i)
809          {
810             JDBCCMPFieldBridge pkField = primaryKeyFields[i];
811             Object JavaDoc fieldValue = pkField.getInstanceValue(ctx);
812
813             // updated pk object with return form set primary key value to
814
// handle single valued non-composit pks and more complicated behivors.
815
pk = pkField.setPrimaryKeyValue(pk, fieldValue);
816          }
817          return pk;
818       }
819       catch(EJBException JavaDoc e)
820       {
821          // to avoid double wrap of EJBExceptions
822
throw e;
823       }
824       catch(Exception JavaDoc e)
825       {
826          // Non recoverable internal exception
827
throw new EJBException JavaDoc("Internal error extracting primary key from " +
828             "instance", e);
829       }
830    }
831
832    public void injectPrimaryKeyIntoInstance(EntityEnterpriseContext ctx, Object JavaDoc pk)
833    {
834       for(int i = 0; i < primaryKeyFields.length; ++i)
835       {
836          JDBCCMPFieldBridge pkField = primaryKeyFields[i];
837          Object JavaDoc fieldValue = pkField.getPrimaryKeyValue(pk);
838          pkField.setInstanceValue(ctx, fieldValue);
839       }
840    }
841
842    int getNextJDBCContextIndex()
843    {
844       return jdbcContextSize++;
845    }
846
847    int addTableField(JDBCCMPFieldBridge field)
848    {
849       JDBCCMPFieldBridge[] tmpFields = tableFields;
850       if(tableFields == null)
851       {
852          tableFields = new JDBCCMPFieldBridge[1];
853       }
854       else
855       {
856          tableFields = new JDBCCMPFieldBridge[tableFields.length + 1];
857          System.arraycopy(tmpFields, 0, tableFields, 0, tmpFields.length);
858       }
859       int index = tableFields.length - 1;
860       tableFields[index] = field;
861
862       return index;
863    }
864
865    public JDBCFieldBridge[] getTableFields()
866    {
867       return tableFields;
868    }
869
870    /**
871     * Marks the context as removed.
872     * @param ctx instance's context
873     */

874    public void setRemoved(EntityEnterpriseContext ctx)
875    {
876       getEntityState(ctx).setRemoved();
877    }
878
879    /**
880     * @param ctx instance's context.
881     * @return true if instance was removed.
882     */

883    public boolean isRemoved(EntityEnterpriseContext ctx)
884    {
885       return getEntityState(ctx).isRemoved();
886    }
887
888    /**
889     * Marks an instance as being removed
890     */

891    public void setIsBeingRemoved(EntityEnterpriseContext ctx)
892    {
893       getEntityState(ctx).setIsBeingRemoved();
894    }
895    
896    /**
897     * @param ctx instance's context.
898     * @return true if instance is being removed.
899     */

900    public boolean isBeingRemoved(EntityEnterpriseContext ctx)
901    {
902       return getEntityState(ctx).isBeingRemoved();
903    }
904
905    /**
906     * Marks the instance as scheduled for cascade delete (not for batch cascade delete)
907     * @param ctx instance's context.
908     */

909    public void scheduleForCascadeDelete(EntityEnterpriseContext ctx)
910    {
911       getEntityState(ctx).scheduleForCascadeDelete();
912       if(log.isTraceEnabled())
913          log.trace("Scheduled for cascade-delete: " + ctx.getId());
914    }
915
916    /**
917     * @param ctx instance's context.
918     * @return true if instance was scheduled for cascade delete (not for batch cascade delete)
919     */

920    public boolean isScheduledForCascadeDelete(EntityEnterpriseContext ctx)
921    {
922       return getEntityState(ctx).isScheduledForCascadeDelete();
923    }
924
925    /**
926     * Marks the instance as scheduled for batch cascade delete (not for cascade delete)
927     * @param ctx instance's context.
928     */

929    public void scheduleForBatchCascadeDelete(EntityEnterpriseContext ctx)
930    {
931       getEntityState(ctx).scheduleForBatchCascadeDelete();
932       if(log.isTraceEnabled())
933          log.trace("Scheduled for batch-cascade-delete: " + ctx.getId());
934    }
935
936    /**
937     * @param ctx instance's context.
938     * @return true if instance was scheduled for batch cascade delete (not for cascade delete)
939     */

940    public boolean isScheduledForBatchCascadeDelete(EntityEnterpriseContext ctx)
941    {
942       return getEntityState(ctx).isScheduledForBatchCascadeDelete();
943    }
944
945    private static EntityState getEntityState(EntityEnterpriseContext ctx)
946    {
947       JDBCContext jdbcCtx = (JDBCContext)ctx.getPersistenceContext();
948       EntityState entityState = jdbcCtx.getEntityState();
949       if(entityState == null)
950          throw new IllegalStateException JavaDoc("Entity state is null.");
951       return entityState;
952    }
953
954    private void loadCMPFields(JDBCEntityMetaData metadata)
955       throws DeploymentException
956    {
957       // only non pk fields are stored here at first and then later
958
// the pk fields are added to the front (makes sql easier to read)
959
List JavaDoc cmpFieldsMD = metadata.getCMPFields();
960       List JavaDoc cmpFieldsList = new ArrayList JavaDoc(cmpFieldsMD.size());
961       // primary key cmp fields
962
List JavaDoc pkFieldsList = new ArrayList JavaDoc(cmpFieldsMD.size());
963
964       // create pk fields
965
for(int i = 0; i < cmpFieldsMD.size(); ++i)
966       {
967          JDBCCMPFieldMetaData fieldMD = (JDBCCMPFieldMetaData)cmpFieldsMD.get(i);
968          if(fieldMD.isPrimaryKeyMember())
969          {
970             JDBCCMPFieldBridge cmpField = createCMPField(metadata, fieldMD);
971             pkFieldsList.add(cmpField);
972          }
973       }
974
975       // create non-pk cmp fields
976
for(int i = 0; i < cmpFieldsMD.size(); ++i)
977       {
978          JDBCCMPFieldMetaData fieldMD = (JDBCCMPFieldMetaData)cmpFieldsMD.get(i);
979          if(!fieldMD.isPrimaryKeyMember())
980          {
981             JDBCCMPFieldBridge cmpField = createCMPField(metadata, fieldMD);
982             cmpFieldsList.add(cmpField);
983          }
984       }
985
986       // save the pk fields in the pk field array
987
primaryKeyFields = new JDBCCMPFieldBridge[pkFieldsList.size()];
988       for(int i = 0; i < pkFieldsList.size(); ++i)
989          primaryKeyFields[i] = (JDBCCMPFieldBridge)pkFieldsList.get(i);
990
991       // add the pk fields to the front of the cmp list, per guarantee above
992
cmpFields = new JDBCCMPFieldBridge[cmpFieldsMD.size() - primaryKeyFields.length];
993       int cmpFieldIndex = 0;
994       for(int i = 0; i < cmpFieldsList.size(); ++i)
995          cmpFields[cmpFieldIndex++] = (JDBCCMPFieldBridge)cmpFieldsList.get(i);
996    }
997
998    private void loadCMRFields(JDBCEntityMetaData metadata)
999       throws DeploymentException
1000   {
1001      cmrFields = new JDBCCMRFieldBridge[metadata.getRelationshipRoles().size()];
1002      // create each field
1003
int cmrFieldIndex = 0;
1004      for(Iterator JavaDoc iter = metadata.getRelationshipRoles().iterator(); iter.hasNext();)
1005      {
1006         JDBCRelationshipRoleMetaData relationshipRole = (JDBCRelationshipRoleMetaData)iter.next();
1007         JDBCCMRFieldBridge cmrField = new JDBCCMRFieldBridge(this, manager, relationshipRole);
1008         cmrFields[cmrFieldIndex++] = cmrField;
1009      }
1010   }
1011
1012   private void loadLoadGroups(JDBCEntityMetaData metadata)
1013      throws DeploymentException
1014   {
1015      loadGroupMasks = new HashMap JavaDoc();
1016
1017      // load optimistic locking mask and add it to all the load group masks
1018
JDBCOptimisticLockingMetaData olMD = metadata.getOptimisticLocking();
1019      if(olMD != null)
1020      {
1021         if(versionField != null)
1022         {
1023            defaultLockGroupMask = new boolean[tableFields.length];
1024            defaultLockGroupMask[versionField.getTableIndex()] = true;
1025            versionField.setLockingStrategy(LockingStrategy.VERSION);
1026         }
1027         else if(olMD.getGroupName() != null)
1028         {
1029            defaultLockGroupMask = loadGroupMask(olMD.getGroupName(), null);
1030            for(int i = 0; i < tableFields.length; ++i)
1031            {
1032               if(defaultLockGroupMask[i])
1033               {
1034                  JDBCCMPFieldBridge tableField = tableFields[i];
1035                  tableField.setLockingStrategy(LockingStrategy.GROUP);
1036                  tableField.addDefaultFlag(ADD_TO_WHERE_ON_UPDATE);
1037               }
1038            }
1039         }
1040         else // read or modified strategy
1041
{
1042            LockingStrategy strategy =
1043               (olMD.getLockingStrategy() == JDBCOptimisticLockingMetaData.READ_STRATEGY ?
1044               LockingStrategy.READ : LockingStrategy.MODIFIED
1045               );
1046            for(int i = 0; i < tableFields.length; ++i)
1047            {
1048               JDBCCMPFieldBridge field = tableFields[i];
1049               if(!field.isPrimaryKeyMember())
1050                  field.setLockingStrategy(strategy);
1051            }
1052         }
1053      }
1054
1055      // add the * load group
1056
boolean[] defaultLoadGroup = new boolean[tableFields.length];
1057      Arrays.fill(defaultLoadGroup, true);
1058      for(int i = 0; i < primaryKeyFields.length; ++i)
1059      {
1060         int tableIndex = primaryKeyFields[i].getTableIndex();
1061         defaultLoadGroup[tableIndex] = false;
1062      }
1063      loadGroupMasks.put(DEFAULT_LOADGROUP_NAME, defaultLoadGroup);
1064
1065      // put each group in the load groups map by group name
1066
Iterator JavaDoc groupNames = metadata.getLoadGroups().keySet().iterator();
1067      while(groupNames.hasNext())
1068      {
1069         // get the group name
1070
String JavaDoc groupName = (String JavaDoc)groupNames.next();
1071         boolean[] loadGroup = loadGroupMask(groupName, defaultLockGroupMask);
1072         loadGroupMasks.put(groupName, loadGroup);
1073      }
1074      loadGroupMasks = Collections.unmodifiableMap(loadGroupMasks);
1075   }
1076
1077   private boolean[] loadGroupMask(String JavaDoc groupName, boolean[] defaultGroup)
1078      throws DeploymentException
1079   {
1080      List JavaDoc fieldNames = metadata.getLoadGroup(groupName);
1081      boolean[] group = new boolean[tableFields.length];
1082      if(defaultGroup != null)
1083         System.arraycopy(defaultGroup, 0, group, 0, group.length);
1084      for(Iterator JavaDoc iter = fieldNames.iterator(); iter.hasNext();)
1085      {
1086         String JavaDoc fieldName = (String JavaDoc)iter.next();
1087         JDBCFieldBridge field = (JDBCFieldBridge)getFieldByName(fieldName);
1088         if(field == null)
1089            throw new DeploymentException(
1090               "Field " + fieldName + " not found for entity " + getEntityName());
1091
1092         if(field instanceof JDBCCMRFieldBridge)
1093         {
1094            JDBCCMRFieldBridge cmrField = (JDBCCMRFieldBridge)field;
1095            if(cmrField.hasForeignKey())
1096            {
1097               JDBCCMPFieldBridge[] fkFields = (JDBCCMPFieldBridge[]) cmrField.getForeignKeyFields();
1098               for(int i = 0; i < fkFields.length; ++i)
1099               {
1100                  group[fkFields[i].getTableIndex()] = true;
1101               }
1102            }
1103            else
1104            {
1105               throw new DeploymentException("Only CMR fields that have " +
1106                  "a foreign-key may be a member of a load group: " +
1107                  "fieldName=" + fieldName);
1108            }
1109         }
1110         else
1111         {
1112            group[((JDBCCMPFieldBridge)field).getTableIndex()] = true;
1113         }
1114      }
1115      return group;
1116   }
1117
1118   private void loadEagerLoadGroup(JDBCEntityMetaData metadata)
1119   {
1120      String JavaDoc eagerLoadGroupName = metadata.getEagerLoadGroup();
1121      if(eagerLoadGroupName == null)
1122      {
1123         // can be null in case of <eager-load-group/>, meaning empty load group
1124
eagerLoadGroupMask = defaultLockGroupMask;
1125      }
1126      else
1127         eagerLoadGroupMask = (boolean[])loadGroupMasks.get(eagerLoadGroupName);
1128   }
1129
1130   private void loadLazyLoadGroups(JDBCEntityMetaData metadata)
1131   {
1132      List JavaDoc lazyGroupNames = metadata.getLazyLoadGroups();
1133      lazyLoadGroupMasks = new ArrayList JavaDoc(lazyGroupNames.size());
1134      for(Iterator JavaDoc lazyLoadGroupNames = lazyGroupNames.iterator(); lazyLoadGroupNames.hasNext();)
1135      {
1136         String JavaDoc lazyLoadGroupName = (String JavaDoc)lazyLoadGroupNames.next();
1137         lazyLoadGroupMasks.add(loadGroupMasks.get(lazyLoadGroupName));
1138      }
1139      lazyLoadGroupMasks = Collections.unmodifiableList(lazyLoadGroupMasks);
1140   }
1141
1142   private JDBCCMPFieldBridge createCMPField(JDBCEntityMetaData metadata,
1143                                             JDBCCMPFieldMetaData cmpFieldMetaData)
1144      throws DeploymentException
1145   {
1146      JDBCCMPFieldBridge cmpField;
1147      if(metadata.isCMP1x())
1148         cmpField = new JDBCCMP1xFieldBridge(manager, cmpFieldMetaData);
1149      else
1150         cmpField = new JDBCCMP2xFieldBridge(manager, cmpFieldMetaData);
1151      return cmpField;
1152   }
1153
1154   private void loadSelectors(JDBCEntityMetaData metadata)
1155   {
1156      // Don't know if this is the best way to do this. Another way would be
1157
// to deligate seletors to the JDBCFindEntitiesCommand, but this is
1158
// easier now.
1159
selectorsByMethod = new HashMap JavaDoc(metadata.getQueries().size());
1160      Iterator JavaDoc definedFinders = manager.getMetaData().getQueries().iterator();
1161      while(definedFinders.hasNext())
1162      {
1163         JDBCQueryMetaData q = (JDBCQueryMetaData)definedFinders.next();
1164         if(q.getMethod().getName().startsWith("ejbSelect"))
1165            selectorsByMethod.put(q.getMethod(), new JDBCSelectorBridge(manager, q));
1166      }
1167      selectorsByMethod = Collections.unmodifiableMap(selectorsByMethod);
1168   }
1169
1170   private void addCMPField(JDBCCMPFieldBridge field)
1171   {
1172      JDBCCMPFieldBridge[] tmpCMPFields = cmpFields;
1173      cmpFields = new JDBCCMPFieldBridge[cmpFields.length + 1];
1174      System.arraycopy(tmpCMPFields, 0, cmpFields, 0, tmpCMPFields.length);
1175      cmpFields[tmpCMPFields.length] = field;
1176   }
1177
1178   public class EntityState
1179   {
1180      private static final byte REMOVED = 1;
1181      private static final byte SCHEDULED_FOR_CASCADE_DELETE = 2;
1182      private static final byte SCHEDULED_FOR_BATCH_CASCADE_DELETE = 4;
1183      private static final byte IS_BEING_REMOVED = 8;
1184
1185      /** indicates whether ejbCreate method was executed */
1186      private boolean ejbCreateDone = false;
1187      /** indicates whether ejbPostCreate method was executed */
1188      private boolean ejbPostCreateDone = false;
1189
1190      private byte entityFlags;
1191
1192      /** array of field flags*/
1193      private final byte[] fieldFlags = new byte[tableFields.length];
1194
1195      public EntityState()
1196      {
1197         for(int i = 0; i < tableFields.length; ++i)
1198         {
1199            fieldFlags[i] = tableFields[i].getDefaultFlags();
1200         }
1201      }
1202
1203      public void setRemoved()
1204      {
1205         entityFlags |= REMOVED;
1206         entityFlags &= ~(SCHEDULED_FOR_CASCADE_DELETE | SCHEDULED_FOR_BATCH_CASCADE_DELETE | IS_BEING_REMOVED);
1207      }
1208
1209      public boolean isRemoved()
1210      {
1211         return (entityFlags & REMOVED) > 0;
1212      }
1213
1214      public void setIsBeingRemoved()
1215      {
1216         entityFlags |= IS_BEING_REMOVED;
1217      }
1218
1219      public boolean isBeingRemoved()
1220      {
1221         return (entityFlags & IS_BEING_REMOVED) > 0;
1222      }
1223
1224      public void scheduleForCascadeDelete()
1225      {
1226         entityFlags |= SCHEDULED_FOR_CASCADE_DELETE;
1227      }
1228
1229      public boolean isScheduledForCascadeDelete()
1230      {
1231         return (entityFlags & SCHEDULED_FOR_CASCADE_DELETE) > 0;
1232      }
1233
1234      public void scheduleForBatchCascadeDelete()
1235      {
1236         entityFlags |= SCHEDULED_FOR_BATCH_CASCADE_DELETE | SCHEDULED_FOR_CASCADE_DELETE;
1237      }
1238
1239      public boolean isScheduledForBatchCascadeDelete()
1240      {
1241         return (entityFlags & SCHEDULED_FOR_BATCH_CASCADE_DELETE) > 0;
1242      }
1243
1244      public void setCreated()
1245      {
1246         ejbCreateDone = true;
1247         ejbPostCreateDone = true;
1248      }
1249
1250      public boolean isCreated()
1251      {
1252         return ejbCreateDone && ejbPostCreateDone;
1253      }
1254
1255      /**
1256       * @param fieldIndex index of the field
1257       * @return true if the field is loaded
1258       */

1259      public boolean isLoaded(int fieldIndex)
1260      {
1261         return (fieldFlags[fieldIndex] & LOADED) > 0;
1262      }
1263
1264      /**
1265       * Marks the field as loaded.
1266       * @param fieldIndex index of the field.
1267       */

1268      public void setLoaded(int fieldIndex)
1269      {
1270         fieldFlags[fieldIndex] |= LOADED;
1271      }
1272
1273      /**
1274       * Marks the field to be loaded.
1275       * @param fieldIndex index of the field.
1276       */

1277      public void setLoadRequired(int fieldIndex)
1278      {
1279         fieldFlags[fieldIndex] |= LOAD_REQUIRED;
1280      }
1281
1282      /**
1283       * Marks the field to be updated.
1284       * @param fieldIndex index of the field.
1285       */

1286      public void setUpdateRequired(int fieldIndex)
1287      {
1288         fieldFlags[fieldIndex] |= DIRTY;
1289      }
1290
1291      /**
1292       * The field will be checked for dirty state at commit.
1293       * @param fieldIndex index of the field.
1294       */

1295      public void setCheckDirty(int fieldIndex)
1296      {
1297         fieldFlags[fieldIndex] |= CHECK_DIRTY;
1298      }
1299
1300      /**
1301       * @param fieldIndex the index of the field that should be checked for dirty state.
1302       * @return true if the field should be checked for dirty state.
1303       */

1304      public boolean isCheckDirty(int fieldIndex)
1305      {
1306         return (fieldFlags[fieldIndex] & CHECK_DIRTY) > 0;
1307      }
1308
1309      /**
1310       * Marks the field as clean.
1311       * @param fieldIndex nextIndex of the field.
1312       */

1313      public void setClean(int fieldIndex)
1314      {
1315         fieldFlags[fieldIndex] &= ~(CHECK_DIRTY | DIRTY | LOCKED);
1316      }
1317
1318      /**
1319       * Resets field flags.
1320       * @param fieldIndex nextIndex of the field.
1321       */

1322      public void resetFlags(int fieldIndex)
1323      {
1324         fieldFlags[fieldIndex] = tableFields[fieldIndex].getDefaultFlags();
1325      }
1326
1327      public FieldIterator getDirtyIterator(EntityEnterpriseContext ctx)
1328      {
1329         return new MaskFieldIterator((byte)(DIRTY | ADD_TO_SET_ON_UPDATE));
1330      }
1331
1332      public boolean hasLockedFields()
1333      {
1334         boolean result = false;
1335         for(int i = 0; i < fieldFlags.length; ++i)
1336         {
1337            if((fieldFlags[i] & (LOCKED | ADD_TO_WHERE_ON_UPDATE)) > 0)
1338            {
1339               result = true;
1340               break;
1341            }
1342         }
1343         return result;
1344      }
1345
1346      public FieldIterator getLockedIterator(EntityEnterpriseContext ctx)
1347      {
1348         return new MaskFieldIterator((byte)(LOCKED | ADD_TO_WHERE_ON_UPDATE));
1349      }
1350
1351      public boolean lockValue(int fieldIndex)
1352      {
1353         boolean lock = false;
1354         byte fieldFlag = fieldFlags[fieldIndex];
1355         if((fieldFlag & LOADED) > 0 && (fieldFlag & LOCKED) == 0)
1356         {
1357            fieldFlags[fieldIndex] |= LOCKED;
1358            lock = true;
1359         }
1360         return lock;
1361      }
1362
1363      public FieldIterator getLoadIterator(EntityEnterpriseContext ctx)
1364      {
1365         return new MaskFieldIterator(LOAD_REQUIRED);
1366      }
1367
1368      // Inner
1369

1370      private class MaskFieldIterator implements FieldIterator
1371      {
1372         private final byte flagMask;
1373         private int nextIndex = 0;
1374         private int curIndex = -1;
1375
1376         public MaskFieldIterator(byte flagMask)
1377         {
1378            this.flagMask = flagMask;
1379         }
1380
1381         public boolean hasNext()
1382         {
1383            while(nextIndex < fieldFlags.length)
1384            {
1385               if((fieldFlags[nextIndex] & flagMask) > 0)
1386               {
1387                  return true;
1388               }
1389
1390               ++nextIndex;
1391            }
1392
1393            return false;
1394         }
1395
1396         public JDBCCMPFieldBridge next()
1397         {
1398            if(!hasNext())
1399               throw new NoSuchElementException JavaDoc();
1400            curIndex = nextIndex;
1401            return tableFields[nextIndex++];
1402         }
1403
1404         public void remove()
1405         {
1406            fieldFlags[curIndex] &= ~flagMask;
1407         }
1408
1409         public void removeAll()
1410         {
1411            int inversedMask = ~flagMask;
1412            for(int i = 0; i < fieldFlags.length; ++i)
1413               fieldFlags[i] &= inversedMask;
1414         }
1415
1416         public void reset()
1417         {
1418            nextIndex = 0;
1419            curIndex = -1;
1420         }
1421      }
1422   }
1423
1424   public static final FieldIterator EMPTY_FIELD_ITERATOR = new FieldIterator()
1425   {
1426      public boolean hasNext()
1427      {
1428         return false;
1429      }
1430
1431      public JDBCCMPFieldBridge next()
1432      {
1433         throw new NoSuchElementException JavaDoc();
1434      }
1435
1436      public void remove()
1437      {
1438         throw new UnsupportedOperationException JavaDoc();
1439      }
1440
1441      public void removeAll()
1442      {
1443         throw new UnsupportedOperationException JavaDoc();
1444      }
1445
1446      public void reset()
1447      {
1448      }
1449   };
1450
1451   public static interface FieldIterator
1452   {
1453      /**
1454       * @return true if there are more fields to iterate through.
1455       */

1456      boolean hasNext();
1457
1458      /**
1459       * @return the next field.
1460       */

1461      JDBCCMPFieldBridge next();
1462
1463      /**
1464       * Removes the current field from the iterator (not from the underlying array or another source)
1465       */

1466      void remove();
1467
1468      /**
1469       * Removes all the fields from the iterator (not from the underlying array or another source).
1470       */

1471      void removeAll();
1472
1473      /**
1474       * Resets the current position to the first field.
1475       */

1476      void reset();
1477   }
1478}
1479
Popular Tags