KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc2 > bridge > JDBCCMRFieldBridge2


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.jdbc2.bridge;
23
24 import org.jboss.ejb.plugins.cmp.bridge.EntityBridge;
25 import org.jboss.ejb.plugins.cmp.bridge.FieldBridge;
26 import org.jboss.ejb.plugins.cmp.jdbc2.JDBCStoreManager2;
27 import org.jboss.ejb.plugins.cmp.jdbc2.schema.EntityTable;
28 import org.jboss.ejb.plugins.cmp.jdbc2.schema.RelationTable;
29 import org.jboss.ejb.plugins.cmp.jdbc2.schema.Cache;
30 import org.jboss.ejb.plugins.cmp.jdbc2.PersistentContext;
31 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData;
32 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
33 import org.jboss.ejb.plugins.cmp.jdbc.JDBCUtil;
34 import org.jboss.ejb.plugins.cmp.jdbc.JDBCType;
35 import org.jboss.ejb.plugins.cmp.jdbc.JDBCEntityPersistenceStore;
36 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
37 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge;
38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge;
39 import org.jboss.ejb.plugins.cmp.jdbc.bridge.CMRInvocation;
40 import org.jboss.ejb.plugins.cmp.jdbc.bridge.CMRMessage;
41 import org.jboss.ejb.plugins.cmp.ejbql.Catalog;
42 import org.jboss.ejb.plugins.lock.Entrancy;
43 import org.jboss.ejb.EntityEnterpriseContext;
44 import org.jboss.ejb.EntityContainer;
45 import org.jboss.ejb.EntityCache;
46 import org.jboss.ejb.LocalProxyFactory;
47 import org.jboss.deployment.DeploymentException;
48 import org.jboss.logging.Logger;
49 import org.jboss.security.SecurityAssociation;
50 import org.jboss.invocation.InvocationType;
51
52 import javax.ejb.EJBException JavaDoc;
53 import javax.ejb.EJBLocalObject JavaDoc;
54 import javax.ejb.RemoveException JavaDoc;
55 import javax.ejb.NoSuchObjectLocalException JavaDoc;
56 import javax.transaction.Transaction JavaDoc;
57 import javax.transaction.TransactionManager JavaDoc;
58 import javax.transaction.SystemException JavaDoc;
59 import java.util.Collection JavaDoc;
60 import java.util.List JavaDoc;
61 import java.util.ArrayList JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.HashMap JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.Set JavaDoc;
66 import java.util.Collections JavaDoc;
67 import java.util.HashSet JavaDoc;
68 import java.util.ConcurrentModificationException JavaDoc;
69 import java.sql.PreparedStatement JavaDoc;
70 import java.sql.Connection JavaDoc;
71 import java.sql.ResultSet JavaDoc;
72 import java.sql.SQLException JavaDoc;
73 import java.lang.reflect.Array JavaDoc;
74 import java.security.AccessController JavaDoc;
75 import java.security.PrivilegedAction JavaDoc;
76 import java.security.Principal JavaDoc;
77
78
79 /**
80  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
81  * @version <tt>$Revision: 58402 $</tt>
82  */

83 public class JDBCCMRFieldBridge2
84    extends JDBCAbstractCMRFieldBridge
85 {
86    private final JDBCRelationshipRoleMetaData metadata;
87    private final JDBCStoreManager2 manager;
88    private final JDBCEntityBridge2 entity;
89    private final int cmrIndex;
90    private final Logger log;
91
92    private JDBCEntityBridge2 relatedEntity;
93    private JDBCCMRFieldBridge2 relatedCMRField;
94    private EntityContainer relatedContainer;
95
96    private JDBCCMPFieldBridge2[] tableKeyFields;
97    private JDBCCMPFieldBridge2[] foreignKeyFields;
98    private JDBCCMPFieldBridge2[] relatedPKFields;
99
100    private CMRFieldLoader loader;
101    private RelationTable relationTable;
102
103    private EntityTable.ForeignKeyConstraint fkConstraint;
104
105    private final TransactionManager JavaDoc tm;
106
107    public JDBCCMRFieldBridge2(JDBCEntityBridge2 entityBridge,
108                               JDBCStoreManager2 manager,
109                               JDBCRelationshipRoleMetaData metadata)
110    {
111       this.manager = manager;
112       this.entity = entityBridge;
113       this.metadata = metadata;
114       cmrIndex = entity.getNextCMRIndex();
115       tm = manager.getContainer().getTransactionManager();
116
117       log = Logger.getLogger(getClass().getName() + "." + entity.getEntityName() + "#" + getFieldName());
118    }
119
120    // Public
121

122    public void resolveRelationship() throws DeploymentException
123    {
124       //
125
// Set handles to the related entity's container, cache, manager, and invoker
126
//
127

128       // Related Entity Name
129
String JavaDoc relatedEntityName = metadata.getRelatedRole().getEntity().getName();
130
131       // Related Entity
132
Catalog catalog = (Catalog)manager.getApplicationData("CATALOG");
133       relatedEntity = (JDBCEntityBridge2)catalog.getEntityByEJBName(relatedEntityName);
134       if(relatedEntity == null)
135       {
136          throw new DeploymentException("Related entity not found: "
137             +
138             "entity="
139             +
140             entity.getEntityName()
141             +
142             ", "
143             +
144             "cmrField="
145             +
146             getFieldName()
147             +
148             ", " +
149             "relatedEntity=" + relatedEntityName
150          );
151       }
152
153       // Related CMR Field
154
JDBCCMRFieldBridge2[] cmrFields = (JDBCCMRFieldBridge2[])relatedEntity.getCMRFields();
155       for(int i = 0; i < cmrFields.length; ++i)
156       {
157          JDBCCMRFieldBridge2 cmrField = cmrFields[i];
158          if(metadata.getRelatedRole() == cmrField.getMetaData())
159          {
160             relatedCMRField = cmrField;
161             break;
162          }
163       }
164
165       // if we didn't find the related CMR field throw an exception with a detailed message
166
if(relatedCMRField == null)
167       {
168          String JavaDoc message = "Related CMR field not found in " +
169             relatedEntity.getEntityName() + " for relationship from ";
170
171          message += entity.getEntityName() + ".";
172          if(getFieldName() != null)
173          {
174             message += getFieldName();
175          }
176          else
177          {
178             message += "<no-field>";
179          }
180
181          message += " to ";
182          message += relatedEntityName + ".";
183          if(metadata.getRelatedRole().getCMRFieldName() != null)
184          {
185             message += metadata.getRelatedRole().getCMRFieldName();
186          }
187          else
188          {
189             message += "<no-field>";
190          }
191
192          throw new DeploymentException(message);
193       }
194
195       // Related Container
196
relatedContainer = relatedEntity.getContainer();
197
198       //
199
// Initialize the key fields
200
//
201
if(metadata.getRelationMetaData().isTableMappingStyle())
202       {
203          // initialize relation table key fields
204
Collection JavaDoc tableKeys = metadata.getKeyFields();
205          List JavaDoc keyFieldsList = new ArrayList JavaDoc(tableKeys.size());
206
207          // first phase is to create fk fields
208
Map JavaDoc pkFieldsToFKFields = new HashMap JavaDoc(tableKeys.size());
209          for(Iterator JavaDoc i = tableKeys.iterator(); i.hasNext();)
210          {
211             JDBCCMPFieldMetaData cmpFieldMetaData = (JDBCCMPFieldMetaData)i.next();
212             FieldBridge pkField = entity.getFieldByName(cmpFieldMetaData.getFieldName());
213             if(pkField == null)
214             {
215                throw new DeploymentException("Primary key not found for key-field " + cmpFieldMetaData.getFieldName());
216             }
217             pkFieldsToFKFields.put(pkField, new JDBCCMPFieldBridge2(manager, entity, cmpFieldMetaData, -1));
218          }
219
220          // second step is to order fk fields to match the order of pk fields
221
JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
222          for(int i = 0; i < pkFields.length; ++i)
223          {
224             Object JavaDoc fkField = pkFieldsToFKFields.get(pkFields[i]);
225             if(fkField == null)
226             {
227                throw new DeploymentException("Primary key " + pkFields[i].getFieldName() + " is not mapped.");
228             }
229             keyFieldsList.add(fkField);
230          }
231          tableKeyFields = (JDBCCMPFieldBridge2[])keyFieldsList.toArray(new JDBCCMPFieldBridge2[keyFieldsList.size()]);
232       }
233       else
234       {
235          initializeForeignKeyFields();
236       }
237    }
238
239    public void initLoader() throws DeploymentException
240    {
241       if(metadata.getRelationMetaData().isTableMappingStyle())
242       {
243          relationTable = relatedCMRField.getRelationTable();
244          loader = new RelationTableLoader();
245       }
246       else
247       {
248          if(foreignKeyFields != null)
249          {
250             loader = new ContextForeignKeyLoader();
251          }
252          else
253          {
254             loader = new ForeignKeyLoader();
255          }
256       }
257    }
258
259    public JDBCRelationshipRoleMetaData getMetaData()
260    {
261       return metadata;
262    }
263
264    public boolean removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
265    {
266       FieldState state = getFieldState(ctx);
267       return state.removeRelatedId(ctx, relatedId);
268    }
269
270    public boolean addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
271    {
272       FieldState state = getFieldState(ctx);
273       return state.addRelatedId(ctx, relatedId);
274    }
275
276    public void remove(EntityEnterpriseContext ctx) throws RemoveException JavaDoc
277    {
278       if(metadata.getRelatedRole().isCascadeDelete())
279       {
280          FieldState state = getFieldState(ctx);
281          state.cascadeDelete(ctx);
282       }
283       else
284       {
285          destroyExistingRelationships(ctx);
286       }
287    }
288
289    public void destroyExistingRelationships(EntityEnterpriseContext ctx)
290    {
291       FieldState state = getFieldState(ctx);
292       state.destroyExistingRelationships(ctx);
293    }
294
295    public JDBCFieldBridge[] getTableKeyFields()
296    {
297       return tableKeyFields;
298    }
299
300    public JDBCEntityPersistenceStore getManager()
301    {
302       return manager;
303    }
304
305    public boolean hasForeignKey()
306    {
307       return foreignKeyFields != null;
308    }
309
310    public JDBCAbstractCMRFieldBridge getRelatedCMRField()
311    {
312       return this.relatedCMRField;
313    }
314
315    public JDBCFieldBridge[] getForeignKeyFields()
316    {
317       return foreignKeyFields;
318    }
319
320    public JDBCCMRFieldBridge2 getRelatedField()
321    {
322       return relatedCMRField;
323    }
324
325    public JDBCAbstractEntityBridge getEntity()
326    {
327       return entity;
328    }
329
330    public String JavaDoc getQualifiedTableName()
331    {
332       return relationTable.getTableName();
333    }
334
335    public String JavaDoc getTableName()
336    {
337       throw new UnsupportedOperationException JavaDoc();
338    }
339
340    // JDBCFieldBridge implementation
341

342    public JDBCType getJDBCType()
343    {
344       throw new UnsupportedOperationException JavaDoc();
345    }
346
347    public boolean isPrimaryKeyMember()
348    {
349       throw new UnsupportedOperationException JavaDoc();
350    }
351
352    public boolean isReadOnly()
353    {
354       throw new UnsupportedOperationException JavaDoc();
355    }
356
357    public boolean isReadTimedOut(EntityEnterpriseContext ctx)
358    {
359       throw new UnsupportedOperationException JavaDoc();
360    }
361
362    public boolean isLoaded(EntityEnterpriseContext ctx)
363    {
364       throw new UnsupportedOperationException JavaDoc();
365    }
366
367    public void initInstance(EntityEnterpriseContext ctx)
368    {
369       getFieldState(ctx).init();
370    }
371
372    public void resetPersistenceContext(EntityEnterpriseContext ctx)
373    {
374       throw new UnsupportedOperationException JavaDoc();
375    }
376
377    public int setInstanceParameters(PreparedStatement JavaDoc ps, int parameterIndex, EntityEnterpriseContext ctx)
378    {
379       throw new UnsupportedOperationException JavaDoc();
380    }
381
382    public Object JavaDoc getInstanceValue(EntityEnterpriseContext ctx)
383    {
384       throw new UnsupportedOperationException JavaDoc();
385    }
386
387    public void setInstanceValue(EntityEnterpriseContext ctx, Object JavaDoc value)
388    {
389       throw new UnsupportedOperationException JavaDoc();
390    }
391
392    public int loadInstanceResults(ResultSet JavaDoc rs, int parameterIndex, EntityEnterpriseContext ctx)
393    {
394       throw new UnsupportedOperationException JavaDoc();
395    }
396
397    public int loadArgumentResults(ResultSet JavaDoc rs, int parameterIndex, Object JavaDoc[] argumentRef)
398    {
399       throw new UnsupportedOperationException JavaDoc();
400    }
401
402    public boolean isDirty(EntityEnterpriseContext ctx)
403    {
404       return getFieldState(ctx).isModified();
405    }
406
407    public void setClean(EntityEnterpriseContext ctx)
408    {
409       throw new UnsupportedOperationException JavaDoc();
410    }
411
412    public boolean isCMPField()
413    {
414       return false;
415    }
416
417    // CMRFieldBridge implementation
418

419    public String JavaDoc getFieldName()
420    {
421       return metadata.getCMRFieldName();
422    }
423
424    public Object JavaDoc getValue(EntityEnterpriseContext ctx)
425    {
426       FieldState state = getFieldState(ctx);
427       return state.getValue(ctx);
428    }
429
430    public void setValue(EntityEnterpriseContext ctx, Object JavaDoc value)
431    {
432       FieldState state = getFieldState(ctx);
433       state.setValue(ctx, value);
434       state.cacheValue(ctx);
435    }
436
437    public boolean isSingleValued()
438    {
439       return metadata.getRelatedRole().isMultiplicityOne();
440    }
441
442    public EntityBridge getRelatedEntity()
443    {
444       return relatedEntity;
445    }
446
447    // Private
448

449    private void initializeForeignKeyFields() throws DeploymentException
450    {
451       Collection JavaDoc foreignKeys = metadata.getRelatedRole().getKeyFields();
452
453       // temporary map used later to write fk fields in special order
454
Map JavaDoc fkFieldsByRelatedPKFields = new HashMap JavaDoc();
455       for(Iterator JavaDoc i = foreignKeys.iterator(); i.hasNext();)
456       {
457          JDBCCMPFieldMetaData fkFieldMetaData = (JDBCCMPFieldMetaData)i.next();
458          JDBCCMPFieldBridge2 relatedPKField =
459             (JDBCCMPFieldBridge2)relatedEntity.getFieldByName(fkFieldMetaData.getFieldName());
460
461          // now determine whether the fk is mapped to a pk column
462
String JavaDoc fkColumnName = fkFieldMetaData.getColumnName();
463          JDBCCMPFieldBridge2 fkField = null;
464
465          // look among the CMP fields for the field with the same column name
466
JDBCCMPFieldBridge2[] tableFields = (JDBCCMPFieldBridge2[])entity.getTableFields();
467          for(int tableInd = 0; tableInd < tableFields.length && fkField == null; ++tableInd)
468          {
469             JDBCCMPFieldBridge2 cmpField = tableFields[tableInd];
470             if(fkColumnName.equals(cmpField.getColumnName()))
471             {
472                // construct the foreign key field
473
fkField = new JDBCCMPFieldBridge2(cmpField, relatedPKField);
474                /*
475                   cmpField.getManager(), // this cmpField's manager
476                   relatedPKField.getFieldName(),
477                   relatedPKField.getFieldType(),
478                   cmpField.getJDBCType(), // this cmpField's jdbc type
479                   relatedPKField.isReadOnly(),
480                   relatedPKField.getReadTimeOut(),
481                   relatedPKField.getPrimaryKeyClass(),
482                   relatedPKField.getPrimaryKeyField(),
483                   cmpField, // CMP field I am mapped to
484                   this,
485                   fkColumnName
486                );
487                */

488             }
489          }
490
491          // if the fk is not a part of pk then create a new field
492
if(fkField == null)
493          {
494             fkField = entity.addTableField(fkFieldMetaData);
495          }
496          fkFieldsByRelatedPKFields.put(relatedPKField, fkField); // temporary map
497
}
498
499       // Note: this important to order the foreign key fields so that their order matches
500
// the order of related entity's pk fields in case of complex primary keys.
501
// The order is important in fk-constraint generation and in SELECT when loading
502
if(fkFieldsByRelatedPKFields.size() > 0)
503       {
504          JDBCFieldBridge[] pkFields = relatedEntity.getPrimaryKeyFields();
505          List JavaDoc fkList = new ArrayList JavaDoc(pkFields.length);
506          List JavaDoc relatedPKList = new ArrayList JavaDoc(pkFields.length);
507          for(int i = 0; i < pkFields.length; ++i)
508          {
509             JDBCFieldBridge relatedPKField = pkFields[i];
510             JDBCFieldBridge fkField = (JDBCCMPFieldBridge2)fkFieldsByRelatedPKFields.remove(relatedPKField);
511             fkList.add(fkField);
512             relatedPKList.add(relatedPKField);
513          }
514          foreignKeyFields = (JDBCCMPFieldBridge2[])fkList.toArray(new JDBCCMPFieldBridge2[fkList.size()]);
515          relatedPKFields =
516             (JDBCCMPFieldBridge2[])relatedPKList.toArray(new JDBCCMPFieldBridge2[relatedPKList.size()]);
517
518          if(metadata.hasForeignKeyConstraint())
519          {
520             fkConstraint = entity.getTable().addFkConstraint(foreignKeyFields, relatedEntity.getTable());
521          }
522       }
523       else
524       {
525          foreignKeyFields = null;
526          relatedPKFields = null;
527       }
528    }
529
530    private FieldState getFieldState(EntityEnterpriseContext ctx)
531    {
532       PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
533       FieldState state = pctx.getCMRState(cmrIndex);
534       if(state == null)
535       {
536          if(isSingleValued())
537          {
538             state = new SingleValuedFieldState();
539          }
540          else
541          {
542             state = new CollectionValuedFieldState();
543          }
544          pctx.setCMRState(cmrIndex, state);
545       }
546       return state;
547    }
548
549    private void invokeRemoveRelatedId(Object JavaDoc myId, Object JavaDoc relatedId)
550    {
551       try
552       {
553          Transaction JavaDoc tx = getTransaction();
554          EntityCache instanceCache = (EntityCache)manager.getContainer().getInstanceCache();
555
556          /*
557          RelationInterceptor.RelationInvocation invocation =
558             new RelationInterceptor.RelationInvocation(RelationInterceptor.CMRMessage.REMOVE_RELATED_ID);
559          invocation.setId(instanceCache.createCacheKey(myId));
560          invocation.setArguments(new Object[]{this, relatedId});
561          invocation.setTransaction(tx);
562          invocation.setPrincipal(SecurityAssociation.getPrincipal());
563          invocation.setCredential(SecurityAssociation.getCredential());
564          invocation.setType(InvocationType.LOCAL);
565          */

566
567          SecurityActions actions = SecurityActions.UTIL.getSecurityActions();
568
569          CMRInvocation invocation = new CMRInvocation();
570          invocation.setCmrMessage(CMRMessage.REMOVE_RELATION);
571          invocation.setEntrancy(Entrancy.NON_ENTRANT);
572          invocation.setId(instanceCache.createCacheKey(myId));
573          invocation.setArguments(new Object JavaDoc[]{this, relatedId});
574          invocation.setTransaction(tx);
575          invocation.setPrincipal(actions.getPrincipal());
576          invocation.setCredential(actions.getCredential());
577          invocation.setType(InvocationType.LOCAL);
578
579          manager.getContainer().invoke(invocation);
580       }
581       catch(EJBException JavaDoc e)
582       {
583          throw e;
584       }
585       catch(Exception JavaDoc e)
586       {
587          throw new EJBException JavaDoc("Error in invokeRemoveRelatedId()", e);
588       }
589    }
590
591    private void invokeAddRelatedId(Object JavaDoc myId, Object JavaDoc relatedId)
592    {
593       try
594       {
595          Transaction JavaDoc tx = getTransaction();
596          EntityCache instanceCache = (EntityCache)manager.getContainer().getInstanceCache();
597          /*
598          RelationInterceptor.RelationInvocation invocation =
599             new RelationInterceptor.RelationInvocation(RelationInterceptor.CMRMessage.ADD_RELATED_ID);
600          invocation.setId(instanceCache.createCacheKey(myId));
601          invocation.setArguments(new Object[]{this, relatedId});
602          invocation.setTransaction(tx);
603          invocation.setPrincipal(SecurityAssociation.getPrincipal());
604          invocation.setCredential(SecurityAssociation.getCredential());
605          invocation.setType(InvocationType.LOCAL);
606          */

607          SecurityActions actions = SecurityActions.UTIL.getSecurityActions();
608
609          CMRInvocation invocation = new CMRInvocation();
610          invocation.setCmrMessage(CMRMessage.ADD_RELATION);
611          invocation.setEntrancy(Entrancy.NON_ENTRANT);
612          invocation.setId(instanceCache.createCacheKey(myId));
613          invocation.setArguments(new Object JavaDoc[]{this, relatedId});
614          invocation.setTransaction(tx);
615          invocation.setPrincipal(actions.getPrincipal());
616          invocation.setCredential(actions.getCredential());
617          invocation.setType(InvocationType.LOCAL);
618
619          manager.getContainer().invoke(invocation);
620       }
621       catch(EJBException JavaDoc e)
622       {
623          throw e;
624       }
625       catch(Exception JavaDoc e)
626       {
627          throw new EJBException JavaDoc("Error in invokeAddRelatedId()", e);
628       }
629    }
630
631    private Transaction JavaDoc getTransaction() throws SystemException JavaDoc
632    {
633       return tm.getTransaction();
634    }
635
636    private RelationTable getRelationTable() throws DeploymentException
637    {
638       if(relationTable == null)
639       {
640          relationTable = manager.getSchema().createRelationTable(this, relatedCMRField);
641       }
642       return relationTable;
643    }
644
645    private Object JavaDoc getPrimaryKey(Object JavaDoc o)
646    {
647       if(o == null)
648       {
649          throw new IllegalArgumentException JavaDoc("This implementation does not support null members.");
650       }
651
652       if(!relatedEntity.getLocalInterface().isInstance(o))
653       {
654          throw new IllegalArgumentException JavaDoc("Argument must be of type " + entity.getLocalInterface().getName());
655       }
656
657       EJBLocalObject JavaDoc local = (EJBLocalObject JavaDoc)o;
658       try
659       {
660          return local.getPrimaryKey();
661       }
662       catch(NoSuchObjectLocalException JavaDoc e)
663       {
664          throw new IllegalArgumentException JavaDoc(e.getMessage());
665       }
666    }
667
668    // Inner
669

670    public class SingleValuedFieldState
671       implements FieldState
672    {
673       private boolean loaded;
674       private Object JavaDoc value;
675       private EJBLocalObject JavaDoc localObject;
676       private boolean modified;
677
678       public void init()
679       {
680          loaded = true;
681       }
682
683       public Object JavaDoc getValue(EntityEnterpriseContext ctx)
684       {
685          Object JavaDoc value = getLoadedValue(ctx);
686          if(value == null)
687          {
688             localObject = null;
689          }
690          else if(localObject == null)
691          {
692             localObject = relatedContainer.getLocalProxyFactory().getEntityEJBLocalObject(value);
693          }
694          return localObject;
695       }
696
697       public void setValue(EntityEnterpriseContext ctx, Object JavaDoc value)
698       {
699          if(value != null)
700          {
701             Object JavaDoc relatedId = getPrimaryKey(value);
702             addRelatedId(ctx, relatedId);
703             relatedCMRField.invokeAddRelatedId(relatedId, ctx.getId());
704             localObject = (EJBLocalObject JavaDoc)value;
705          }
706          else
707          {
708             destroyExistingRelationships(ctx);
709          }
710       }
711
712       public void cascadeDelete(EntityEnterpriseContext ctx) throws RemoveException JavaDoc
713       {
714          if(manager.registerCascadeDelete(ctx.getId(), ctx.getId()))
715          {
716             EJBLocalObject JavaDoc value = (EJBLocalObject JavaDoc)getValue(ctx);
717             if(value != null)
718             {
719                changeValue(null);
720
721                final Object JavaDoc relatedId = value.getPrimaryKey();
722                final JDBCStoreManager2 relatedManager = (JDBCStoreManager2)relatedEntity.getManager();
723
724                if(!relatedManager.isCascadeDeleted(relatedId))
725                {
726                   value.remove();
727                }
728             }
729
730             manager.unregisterCascadeDelete(ctx.getId());
731          }
732       }
733
734       public void destroyExistingRelationships(EntityEnterpriseContext ctx)
735       {
736          Object JavaDoc value = getLoadedValue(ctx);
737          if(value != null)
738          {
739             removeRelatedId(ctx, value);
740             relatedCMRField.invokeRemoveRelatedId(value, ctx.getId());
741          }
742       }
743
744       public boolean removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
745       {
746          if(hasForeignKey())
747          {
748             getLoadedValue(ctx);
749          }
750
751          changeValue(null);
752          loader.removeRelatedId(ctx, relatedId);
753
754          cacheValue(ctx);
755
756          modified = true;
757
758          return true;
759       }
760
761       public boolean addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
762       {
763          Object JavaDoc value = getLoadedValue(ctx);
764          if(value != null)
765          {
766             relatedCMRField.invokeRemoveRelatedId(value, ctx.getId());
767          }
768
769          changeValue(relatedId);
770          loader.addRelatedId(ctx, relatedId);
771
772          cacheValue(ctx);
773
774          modified = true;
775
776          return true;
777       }
778
779       public void addLoadedPk(Object JavaDoc pk)
780       {
781          if(loaded)
782          {
783             throw new IllegalStateException JavaDoc(entity.getEntityName()
784                +
785                "."
786                +
787                getFieldName()
788                +
789                " single-valued CMR field is already loaded. Check the database for consistancy. "
790                + " current value=" + value + ", loaded value=" + pk
791             );
792          }
793
794          changeValue(pk);
795       }
796
797       public Object JavaDoc loadFromCache(Object JavaDoc value)
798       {
799          if(value != null)
800          {
801             changeValue(NULL_VALUE == value ? null : value);
802          }
803          return value;
804       }
805
806       public Object JavaDoc getCachedValue()
807       {
808          return value == null ? NULL_VALUE : value;
809       }
810
811       public void cacheValue(EntityEnterpriseContext ctx)
812       {
813          PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
814          pctx.cacheRelations(cmrIndex, this);
815       }
816
817       public boolean isModified()
818       {
819          return modified;
820       }
821
822       // Private
823

824       private void changeValue(Object JavaDoc newValue)
825       {
826          this.value = newValue;
827          this.localObject = null;
828          loaded = true;
829       }
830
831       private Object JavaDoc getLoadedValue(EntityEnterpriseContext ctx)
832       {
833          if(!loaded)
834          {
835             PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
836             pctx.loadCachedRelations(cmrIndex, this);
837             if(!loaded)
838             {
839                loader.load(ctx, this);
840                loaded = true;
841                cacheValue(ctx);
842             }
843          }
844          return value;
845       }
846    }
847
848    public class CollectionValuedFieldState
849       implements FieldState
850    {
851       private boolean loaded;
852       private Set JavaDoc value;
853       private CMRSet cmrSet;
854
855       private Set JavaDoc removedWhileNotLoaded;
856       private Set JavaDoc addedWhileNotLoaded;
857
858       private boolean modified;
859
860       public void init()
861       {
862          loaded = true;
863          value = new HashSet JavaDoc();
864       }
865
866       public Object JavaDoc getValue(EntityEnterpriseContext ctx)
867       {
868          if(cmrSet == null)
869          {
870             cmrSet = new CMRSet(ctx, this);
871          }
872          return cmrSet;
873       }
874
875       public void setValue(EntityEnterpriseContext ctx, Object JavaDoc value)
876       {
877          if(value == null)
878          {
879             throw new IllegalArgumentException JavaDoc("Can't set collection-valued CMR field to null: " +
880                entity.getEntityName() + "." + getFieldName()
881             );
882          }
883
884          destroyExistingRelationships(ctx);
885
886          Collection JavaDoc newValue = (Collection JavaDoc)value;
887          if(!newValue.isEmpty())
888          {
889             Set JavaDoc copy = new HashSet JavaDoc(newValue);
890             for(Iterator JavaDoc iter = copy.iterator(); iter.hasNext();)
891             {
892                Object JavaDoc relatedId = getPrimaryKey(iter.next());
893                addRelatedId(ctx, relatedId);
894                relatedCMRField.invokeAddRelatedId(relatedId, ctx.getId());
895                loader.addRelatedId(ctx, relatedId);
896             }
897          }
898       }
899
900       public void cascadeDelete(EntityEnterpriseContext ctx) throws RemoveException JavaDoc
901       {
902          Collection JavaDoc value = (Collection JavaDoc)getValue(ctx);
903          if(!value.isEmpty())
904          {
905             EJBLocalObject JavaDoc[] locals = (EJBLocalObject JavaDoc[])value.toArray();
906             for(int i = 0; i < locals.length; ++i)
907             {
908                locals[i].remove();
909             }
910          }
911       }
912
913       public void destroyExistingRelationships(EntityEnterpriseContext ctx)
914       {
915          Set JavaDoc value = getLoadedValue(ctx);
916          if(!value.isEmpty())
917          {
918             Object JavaDoc[] copy = value.toArray();
919             for(int i = 0; i < copy.length; ++i)
920             {
921                Object JavaDoc relatedId = copy[i];
922                removeRelatedId(ctx, relatedId);
923                relatedCMRField.invokeRemoveRelatedId(relatedId, ctx.getId());
924                loader.removeRelatedId(ctx, relatedId);
925             }
926          }
927       }
928
929       public boolean removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
930       {
931          boolean removed = false;
932          if(loaded)
933          {
934             Set JavaDoc value = getLoadedValue(ctx);
935             if(!value.isEmpty())
936             {
937                removed = value.remove(relatedId);
938             }
939          }
940          else
941          {
942             loadOnlyFromCache(ctx);
943             if(loaded)
944             {
945                Set JavaDoc value = getLoadedValue(ctx);
946                if(!value.isEmpty())
947                {
948                   removed = value.remove(relatedId);
949                }
950             }
951             else
952             {
953                removed = removeWhileNotLoaded(relatedId);
954             }
955          }
956
957          modified = true;
958
959          if(removed)
960          {
961             ((PersistentContext)ctx.getPersistenceContext()).setDirtyRelations();
962          }
963
964          return removed;
965       }
966
967       public boolean addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
968       {
969          boolean added;
970          if(loaded)
971          {
972             Set JavaDoc value = getLoadedValue(ctx);
973             added = value.add(relatedId);
974          }
975          else
976          {
977             loadOnlyFromCache(ctx);
978             if(loaded)
979             {
980                Set JavaDoc value = getLoadedValue(ctx);
981                added = value.add(relatedId);
982             }
983             else
984             {
985                added = addWhileNotLoaded(relatedId);
986             }
987          }
988
989          modified = true;
990
991          if(added)
992          {
993             ((PersistentContext)ctx.getPersistenceContext()).setDirtyRelations();
994          }
995
996          return added;
997       }
998
999       public void addLoadedPk(Object JavaDoc pk)
1000      {
1001         if(loaded)
1002         {
1003            throw new IllegalStateException JavaDoc(entity.getEntityName()
1004               +
1005               "."
1006               +
1007               getFieldName()
1008               +
1009               " collection-valued CMR field is already loaded. Check the database for consistancy. "
1010               + " current value=" + value + ", loaded value=" + pk
1011            );
1012         }
1013
1014         if(pk != null)
1015         {
1016            value.add(pk);
1017         }
1018      }
1019
1020      public Object JavaDoc loadFromCache(Object JavaDoc value)
1021      {
1022         if(value != null)
1023         {
1024            value = this.value = new HashSet JavaDoc((Set JavaDoc)value);
1025            loaded = true;
1026         }
1027         return value;
1028      }
1029
1030      public Object JavaDoc getCachedValue()
1031      {
1032         return value;
1033      }
1034
1035      public void cacheValue(EntityEnterpriseContext ctx)
1036      {
1037         PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
1038         pctx.cacheRelations(cmrIndex, this);
1039      }
1040
1041      public boolean isModified()
1042      {
1043         return modified;
1044      }
1045
1046      // Private
1047

1048      private Set JavaDoc getLoadedValue(EntityEnterpriseContext ctx)
1049      {
1050         if(!loaded)
1051         {
1052            loadOnlyFromCache(ctx);
1053
1054            if(!loaded)
1055            {
1056               if(value == null || value == Collections.EMPTY_SET)
1057               {
1058                  value = new HashSet JavaDoc();
1059               }
1060
1061               loader.load(ctx, this);
1062               cacheValue(ctx);
1063
1064               loaded = true;
1065            }
1066
1067            if(addedWhileNotLoaded != null)
1068            {
1069               value.addAll(addedWhileNotLoaded);
1070               addedWhileNotLoaded = null;
1071            }
1072
1073            if(removedWhileNotLoaded != null)
1074            {
1075               value.removeAll(removedWhileNotLoaded);
1076               removedWhileNotLoaded = null;
1077            }
1078         }
1079         return value;
1080      }
1081
1082      private void loadOnlyFromCache(EntityEnterpriseContext ctx)
1083      {
1084         PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
1085         pctx.loadCachedRelations(cmrIndex, this);
1086      }
1087
1088      private boolean removeWhileNotLoaded(Object JavaDoc relatedId)
1089      {
1090         boolean removed = false;
1091         if(addedWhileNotLoaded != null)
1092         {
1093            removed = addedWhileNotLoaded.remove(relatedId);
1094         }
1095
1096         if(!removed)
1097         {
1098            if(removedWhileNotLoaded == null)
1099            {
1100               removedWhileNotLoaded = new HashSet JavaDoc();
1101            }
1102            removed = removedWhileNotLoaded.add(relatedId);
1103         }
1104
1105         if(log.isTraceEnabled() && removed)
1106         {
1107            log.trace("removed while not loaded: relatedId=" + relatedId);
1108         }
1109
1110         return removed;
1111      }
1112
1113      private boolean addWhileNotLoaded(Object JavaDoc relatedId)
1114      {
1115         boolean added = false;
1116         if(removedWhileNotLoaded != null)
1117         {
1118            added = removedWhileNotLoaded.remove(relatedId);
1119         }
1120
1121         if(!added)
1122         {
1123            if(addedWhileNotLoaded == null)
1124            {
1125               addedWhileNotLoaded = new HashSet JavaDoc();
1126            }
1127            added = addedWhileNotLoaded.add(relatedId);
1128         }
1129
1130         if(log.isTraceEnabled() && added)
1131         {
1132            log.trace("added while not loaded: relatedId=" + relatedId);
1133         }
1134
1135         return added;
1136      }
1137   }
1138
1139   public interface FieldState
1140      extends Cache.CacheLoader
1141   {
1142      Object JavaDoc NULL_VALUE = new Object JavaDoc();
1143
1144      void init();
1145
1146      Object JavaDoc getValue(EntityEnterpriseContext ctx);
1147
1148      void cascadeDelete(EntityEnterpriseContext ctx) throws RemoveException JavaDoc;
1149
1150      void destroyExistingRelationships(EntityEnterpriseContext ctx);
1151
1152      void setValue(EntityEnterpriseContext ctx, Object JavaDoc value);
1153
1154      boolean removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId);
1155
1156      boolean addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc value);
1157
1158      void addLoadedPk(Object JavaDoc pk);
1159
1160      void cacheValue(EntityEnterpriseContext ctx);
1161
1162      boolean isModified();
1163   }
1164
1165   private class RelationTableLoader
1166      implements CMRFieldLoader
1167   {
1168      private final String JavaDoc loadSql;
1169
1170      public RelationTableLoader()
1171      {
1172         StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
1173         sql.append("select ");
1174
1175         String JavaDoc relatedTable = relatedEntity.getQualifiedTableName();
1176         String JavaDoc relationTable = metadata.getRelationMetaData().getDefaultTableName();
1177
1178         relatedEntity.getTable().appendColumnNames((JDBCCMPFieldBridge2[])relatedEntity.getTableFields(),
1179            relatedTable,
1180            sql
1181         );
1182         sql.append(" from ")
1183            .append(relatedTable)
1184            .append(" inner join ")
1185            .append(relationTable)
1186            .append(" on ");
1187
1188         JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[])relatedEntity.getPrimaryKeyFields();
1189         for(int i = 0; i < pkFields.length; ++i)
1190         {
1191            if(i > 0)
1192            {
1193               sql.append(" and ");
1194            }
1195
1196            sql.append(relatedTable).append('.').append(pkFields[i].getColumnName())
1197               .append('=')
1198               .append(relationTable).append('.').append(relatedCMRField.tableKeyFields[i].getColumnName());
1199         }
1200
1201         /*
1202         sql.append(" inner join ")
1203            .append(myTable)
1204            .append(" on ");
1205
1206         String myTable = entity.getQualifiedTableName();
1207         pkFields = entity.getPrimaryKeyFields();
1208         for(int i = 0; i < pkFields.length; ++i)
1209         {
1210            if(i > 0)
1211            {
1212               sql.append(", ");
1213            }
1214
1215            sql.append(myTable).append('.').append(pkFields[i].getColumnName())
1216               .append('=')
1217               .append(relationTable).append('.').append(tableKeyFields[i].getColumnName());
1218         }
1219         */

1220
1221         sql.append(" where ");
1222         for(int i = 0; i < tableKeyFields.length; ++i)
1223         {
1224            if(i > 0)
1225            {
1226               sql.append(" and ");
1227            }
1228
1229            sql.append(relationTable).append('.').append(tableKeyFields[i].getColumnName()).append("=?");
1230         }
1231
1232         loadSql = sql.toString();
1233
1234         if(log.isTraceEnabled())
1235         {
1236            log.trace("load sql: " + loadSql);
1237         }
1238      }
1239
1240      public void load(EntityEnterpriseContext ctx, FieldState state)
1241      {
1242         Object JavaDoc value;
1243         EntityTable relatedTable = relatedEntity.getTable();
1244
1245         Connection JavaDoc con = null;
1246         PreparedStatement JavaDoc ps = null;
1247         ResultSet JavaDoc rs = null;
1248         try
1249         {
1250            if(log.isDebugEnabled())
1251            {
1252               log.debug("executing: " + loadSql);
1253            }
1254
1255            con = relatedTable.getDataSource().getConnection();
1256            ps = con.prepareStatement(loadSql);
1257
1258            JDBCCMPFieldBridge2[] pkFields = (JDBCCMPFieldBridge2[])entity.getPrimaryKeyFields();
1259
1260            Object JavaDoc myPk = ctx.getId();
1261            int paramInd = 1;
1262            for(int i = 0; i < pkFields.length; ++i)
1263            {
1264               JDBCCMPFieldBridge2 pkField = pkFields[i];
1265               Object JavaDoc fieldValue = pkField.getPrimaryKeyValue(myPk);
1266
1267               JDBCCMPFieldBridge2 relatedFkField = tableKeyFields[i];
1268               relatedFkField.setArgumentParameters(ps, paramInd++, fieldValue);
1269            }
1270
1271            rs = ps.executeQuery();
1272
1273            while(rs.next())
1274            {
1275               value = relatedTable.loadRow(rs, false);
1276               state.addLoadedPk(value);
1277            }
1278         }
1279         catch(SQLException JavaDoc e)
1280         {
1281            log.error("Failed to load related role: ejb-name="
1282               +
1283               entity.getEntityName() +
1284               ", cmr-field=" + getFieldName() + ": " + e.getMessage(), e
1285            );
1286            throw new EJBException JavaDoc("Failed to load related role: ejb-name="
1287               +
1288               entity.getEntityName() +
1289               ", cmr-field=" + getFieldName() + ": " + e.getMessage(), e
1290            );
1291         }
1292         finally
1293         {
1294            JDBCUtil.safeClose(rs);
1295            JDBCUtil.safeClose(ps);
1296            JDBCUtil.safeClose(con);
1297         }
1298      }
1299
1300      public void removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1301      {
1302         relationTable.removeRelation(JDBCCMRFieldBridge2.this, ctx.getId(), relatedCMRField, relatedId);
1303      }
1304
1305      public void addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1306      {
1307         relationTable.addRelation(JDBCCMRFieldBridge2.this, ctx.getId(), relatedCMRField, relatedId);
1308      }
1309   }
1310
1311   private class ForeignKeyLoader
1312      implements CMRFieldLoader
1313   {
1314      private final String JavaDoc loadSql;
1315
1316      public ForeignKeyLoader()
1317      {
1318         StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
1319         sql.append("select ");
1320         relatedEntity.getTable().appendColumnNames((JDBCCMPFieldBridge2[])relatedEntity.getTableFields(), null, sql);
1321         sql.append(" from ").append(relatedEntity.getQualifiedTableName()).append(" where ");
1322
1323         JDBCCMPFieldBridge2[] relatedFkFields = relatedCMRField.foreignKeyFields;
1324         sql.append(relatedFkFields[0].getColumnName()).append("=?");
1325         for(int i = 1; i < relatedFkFields.length; ++i)
1326         {
1327            JDBCCMPFieldBridge2 relatedFkField = relatedFkFields[i];
1328            sql.append(" and ").append(relatedFkField.getColumnName()).append("=?");
1329         }
1330
1331         loadSql = sql.toString();
1332
1333         if(log.isTraceEnabled())
1334         {
1335            log.trace("load sql: " + loadSql);
1336         }
1337      }
1338
1339      public void load(EntityEnterpriseContext ctx, FieldState state)
1340      {
1341         Object JavaDoc value;
1342         EntityTable relatedTable = relatedEntity.getTable();
1343
1344         Connection JavaDoc con = null;
1345         PreparedStatement JavaDoc ps = null;
1346         ResultSet JavaDoc rs = null;
1347         try
1348         {
1349            if(log.isDebugEnabled())
1350            {
1351               log.debug("executing: " + loadSql);
1352            }
1353
1354            con = relatedTable.getDataSource().getConnection();
1355            ps = con.prepareStatement(loadSql);
1356
1357            JDBCCMPFieldBridge2[] relatedFkFields = relatedCMRField.foreignKeyFields;
1358            JDBCCMPFieldBridge2[] myPkFields = relatedCMRField.relatedPKFields;
1359
1360            Object JavaDoc myPk = ctx.getId();
1361            int paramInd = 1;
1362            for(int i = 0; i < relatedFkFields.length; ++i)
1363            {
1364               JDBCCMPFieldBridge2 myPkField = myPkFields[i];
1365               Object JavaDoc fieldValue = myPkField.getPrimaryKeyValue(myPk);
1366
1367               JDBCCMPFieldBridge2 relatedFkField = relatedFkFields[i];
1368               relatedFkField.setArgumentParameters(ps, paramInd++, fieldValue);
1369            }
1370
1371            rs = ps.executeQuery();
1372
1373            while(rs.next())
1374            {
1375               value = relatedTable.loadRow(rs, false);
1376               state.addLoadedPk(value);
1377            }
1378         }
1379         catch(SQLException JavaDoc e)
1380         {
1381            log.error("Failed to load related role: ejb-name="
1382               +
1383               entity.getEntityName() +
1384               ", cmr-field=" + getFieldName() + ": " + e.getMessage(), e
1385            );
1386            throw new EJBException JavaDoc("Failed to load related role: ejb-name="
1387               +
1388               entity.getEntityName() +
1389               ", cmr-field=" + getFieldName() + ": " + e.getMessage(), e
1390            );
1391         }
1392         finally
1393         {
1394            JDBCUtil.safeClose(rs);
1395            JDBCUtil.safeClose(ps);
1396            JDBCUtil.safeClose(con);
1397         }
1398      }
1399
1400      public void removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1401      {
1402      }
1403
1404      public void addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1405      {
1406      }
1407   }
1408
1409   private class ContextForeignKeyLoader
1410      implements CMRFieldLoader
1411   {
1412      public void load(EntityEnterpriseContext ctx, FieldState state)
1413      {
1414         Object JavaDoc relatedId = null;
1415         for(int i = 0; i < foreignKeyFields.length; ++i)
1416         {
1417            JDBCCMPFieldBridge2 fkField = foreignKeyFields[i];
1418            Object JavaDoc fkFieldValue = fkField.getValue(ctx);
1419            if(fkFieldValue == null)
1420            {
1421               break;
1422            }
1423
1424            JDBCCMPFieldBridge2 relatedPKField = relatedPKFields[i];
1425            relatedId = relatedPKField.setPrimaryKeyValue(relatedId, fkFieldValue);
1426         }
1427
1428         state.addLoadedPk(relatedId);
1429      }
1430
1431      public void removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1432      {
1433         for(int i = 0; i < foreignKeyFields.length; ++i)
1434         {
1435            foreignKeyFields[i].setValueInternal(ctx, null, fkConstraint == null);
1436         }
1437
1438         if(fkConstraint != null)
1439         {
1440            PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
1441            pctx.nullForeignKey(fkConstraint);
1442         }
1443      }
1444
1445      public void addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId)
1446      {
1447         final boolean markDirty = relatedId != null || fkConstraint == null;
1448         for(int i = 0; i < foreignKeyFields.length; ++i)
1449         {
1450            JDBCCMPFieldBridge2 relatedPKField = relatedPKFields[i];
1451            Object JavaDoc fieldValue = relatedPKField.getPrimaryKeyValue(relatedId);
1452            foreignKeyFields[i].setValueInternal(ctx, fieldValue, markDirty);
1453         }
1454
1455         if(fkConstraint != null)
1456         {
1457            PersistentContext pctx = (PersistentContext)ctx.getPersistenceContext();
1458            if(relatedId == null)
1459            {
1460               pctx.nullForeignKey(fkConstraint);
1461            }
1462            else
1463            {
1464               pctx.nonNullForeignKey(fkConstraint);
1465            }
1466         }
1467      }
1468   }
1469
1470   private interface CMRFieldLoader
1471   {
1472      void load(EntityEnterpriseContext ctx, FieldState state);
1473
1474      void removeRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId);
1475
1476      void addRelatedId(EntityEnterpriseContext ctx, Object JavaDoc relatedId);
1477   }
1478
1479   private class CMRSet
1480      implements Set JavaDoc
1481   {
1482      private final EntityEnterpriseContext ctx;
1483      private final CollectionValuedFieldState state;
1484
1485      public CMRSet(EntityEnterpriseContext ctx, CollectionValuedFieldState state)
1486      {
1487         this.ctx = ctx;
1488         this.state = state;
1489      }
1490
1491      public int size()
1492      {
1493         return state.getLoadedValue(ctx).size();
1494      }
1495
1496      public void clear()
1497      {
1498         destroyExistingRelationships(ctx);
1499      }
1500
1501      public boolean isEmpty()
1502      {
1503         return size() == 0;
1504      }
1505
1506      public boolean add(Object JavaDoc o)
1507      {
1508         Object JavaDoc relatedId = getPrimaryKey(o);
1509         boolean modified = addRelatedId(ctx, relatedId);
1510
1511         if(modified)
1512         {
1513            relatedCMRField.invokeAddRelatedId(relatedId, ctx.getId());
1514            loader.addRelatedId(ctx, relatedId);
1515         }
1516
1517         return modified;
1518      }
1519
1520      public boolean contains(Object JavaDoc o)
1521      {
1522         Object JavaDoc pk = getPrimaryKey(o);
1523         return state.getLoadedValue(ctx).contains(pk);
1524      }
1525
1526      public boolean remove(Object JavaDoc o)
1527      {
1528         Object JavaDoc relatedId = getPrimaryKey(o);
1529         return removeById(relatedId);
1530      }
1531
1532      public boolean addAll(Collection JavaDoc c)
1533      {
1534         if(c == null || c.isEmpty())
1535         {
1536            return false;
1537         }
1538
1539         boolean modified = false;
1540         Object JavaDoc[] copy = c.toArray();
1541         for(int i = 0; i < copy.length; ++i)
1542         {
1543            // not modified || add()
1544
modified = add(copy[i]) || modified;
1545         }
1546
1547         return modified;
1548      }
1549
1550      public boolean containsAll(Collection JavaDoc c)
1551      {
1552         if(c == null || c.isEmpty())
1553         {
1554            return true;
1555         }
1556
1557         Set JavaDoc ids = argumentToIdSet(c);
1558         return state.getLoadedValue(ctx).containsAll(ids);
1559      }
1560
1561      public boolean removeAll(Collection JavaDoc c)
1562      {
1563         if(c == null || c.isEmpty())
1564         {
1565            return false;
1566         }
1567
1568         boolean modified = false;
1569         Object JavaDoc[] copy = c.toArray();
1570         for(int i = 0; i < copy.length; ++i)
1571         {
1572            modified = remove(copy[i]) || modified;
1573         }
1574
1575         return modified;
1576      }
1577
1578      public boolean retainAll(Collection JavaDoc c)
1579      {
1580         Set JavaDoc value = state.getLoadedValue(ctx);
1581         if(c == null || c.isEmpty())
1582         {
1583            if(value.isEmpty())
1584            {
1585               return false;
1586            }
1587            else
1588            {
1589               clear();
1590            }
1591         }
1592
1593         boolean modified = false;
1594         Set JavaDoc idSet = argumentToIdSet(c);
1595         Object JavaDoc[] valueCopy = value.toArray();
1596         for(int i = 0; i < valueCopy.length; ++i)
1597         {
1598            Object JavaDoc id = valueCopy[i];
1599            if(!idSet.contains(id))
1600            {
1601               removeById(id);
1602               modified = true;
1603            }
1604         }
1605
1606         return modified;
1607      }
1608
1609      public Iterator JavaDoc iterator()
1610      {
1611         return new Iterator JavaDoc()
1612         {
1613            // todo get rid of copying
1614
private final Iterator JavaDoc idIter = new HashSet JavaDoc(state.getLoadedValue(ctx)).iterator();
1615            private Object JavaDoc curId;
1616
1617            public void remove()
1618            {
1619               try
1620               {
1621                  idIter.remove();
1622               }
1623               catch(ConcurrentModificationException JavaDoc e)
1624               {
1625                  throw new IllegalStateException JavaDoc(e.getMessage());
1626               }
1627
1628               removeById(curId);
1629            }
1630
1631            public boolean hasNext()
1632            {
1633               try
1634               {
1635                  return idIter.hasNext();
1636               }
1637               catch(ConcurrentModificationException JavaDoc e)
1638               {
1639                  throw new IllegalStateException JavaDoc(e.getMessage());
1640               }
1641            }
1642
1643            public Object JavaDoc next()
1644            {
1645               try
1646               {
1647                  curId = idIter.next();
1648               }
1649               catch(ConcurrentModificationException JavaDoc e)
1650               {
1651                  throw new IllegalStateException JavaDoc(e.getMessage());
1652               }
1653
1654               return relatedContainer.getLocalProxyFactory().getEntityEJBLocalObject(curId);
1655            }
1656         };
1657      }
1658
1659      public Object JavaDoc[] toArray()
1660      {
1661         Set JavaDoc value = state.getLoadedValue(ctx);
1662
1663         Object JavaDoc[] result = (Object JavaDoc[])Array.newInstance(relatedEntity.getLocalInterface(), value.size());
1664
1665         LocalProxyFactory relatedPF = relatedContainer.getLocalProxyFactory();
1666         int i = 0;
1667         for(Iterator JavaDoc iter = value.iterator(); iter.hasNext();)
1668         {
1669            Object JavaDoc id = iter.next();
1670            result[i++] = relatedPF.getEntityEJBLocalObject(id);
1671         }
1672
1673         return result;
1674      }
1675
1676      public Object JavaDoc[] toArray(Object JavaDoc a[])
1677      {
1678         Set JavaDoc value = state.getLoadedValue(ctx);
1679         if(a == null || a.length < value.size())
1680         {
1681            a = (Object JavaDoc[])Array.newInstance(entity.getLocalInterface(), value.size());
1682         }
1683
1684         LocalProxyFactory relatedPF = relatedContainer.getLocalProxyFactory();
1685         int i = 0;
1686         for(Iterator JavaDoc iter = value.iterator(); iter.hasNext();)
1687         {
1688            Object JavaDoc id = iter.next();
1689            a[i++] = relatedPF.getEntityEJBLocalObject(id);
1690         }
1691
1692         return a;
1693      }
1694
1695      public String JavaDoc toString()
1696      {
1697         return state.getLoadedValue(ctx).toString();
1698      }
1699
1700      // Private
1701

1702      private boolean removeById(Object JavaDoc relatedId)
1703      {
1704         boolean modified = removeRelatedId(ctx, relatedId);
1705         if(modified)
1706         {
1707            relatedCMRField.invokeRemoveRelatedId(relatedId, ctx.getId());
1708            loader.removeRelatedId(ctx, relatedId);
1709         }
1710         return modified;
1711      }
1712
1713      private Set JavaDoc argumentToIdSet(Collection JavaDoc c)
1714      {
1715         Set JavaDoc ids = new HashSet JavaDoc();
1716         for(Iterator JavaDoc iter = c.iterator(); iter.hasNext();)
1717         {
1718            Object JavaDoc pk = getPrimaryKey(iter.next());
1719            ids.add(pk);
1720         }
1721         return ids;
1722      }
1723   }
1724
1725   interface SecurityActions
1726   {
1727      class UTIL
1728      {
1729         static SecurityActions getSecurityActions()
1730         {
1731            return System.getSecurityManager() == null ? NON_PRIVILEGED : PRIVILEGED;
1732         }
1733      }
1734
1735      SecurityActions NON_PRIVILEGED = new SecurityActions()
1736      {
1737         public Principal JavaDoc getPrincipal()
1738         {
1739            return SecurityAssociation.getPrincipal();
1740         }
1741
1742         public Object JavaDoc getCredential()
1743         {
1744            return SecurityAssociation.getCredential();
1745         }
1746      };
1747
1748      SecurityActions PRIVILEGED = new SecurityActions()
1749      {
1750         private final PrivilegedAction JavaDoc getPrincipalAction = new PrivilegedAction JavaDoc()
1751         {
1752            public Object JavaDoc run()
1753            {
1754               return SecurityAssociation.getPrincipal();
1755            }
1756         };
1757
1758         private final PrivilegedAction JavaDoc getCredentialAction = new PrivilegedAction JavaDoc()
1759         {
1760            public Object JavaDoc run()
1761            {
1762               return SecurityAssociation.getCredential();
1763            }
1764         };
1765
1766         public Principal JavaDoc getPrincipal()
1767         {
1768            return (Principal JavaDoc)AccessController.doPrivileged(getPrincipalAction);
1769         }
1770
1771         public Object JavaDoc getCredential()
1772         {
1773            return AccessController.doPrivileged(getCredentialAction);
1774         }
1775      };
1776
1777      Principal JavaDoc getPrincipal();
1778
1779      Object JavaDoc getCredential();
1780   }
1781}
1782
Popular Tags