KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > metadata > JDBCRelationshipRoleMetaData


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.metadata;
23
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import org.jboss.deployment.DeploymentException;
32 import org.jboss.metadata.MetaData;
33 import org.jboss.metadata.RelationshipRoleMetaData;
34 import org.w3c.dom.Element JavaDoc;
35
36 /**
37  * Imutable class which represents one ejb-relationship-role element found in
38  * the ejb-jar.xml file's ejb-relation elements.
39  *
40  * @author <a HREF="mailto:dain@daingroup.com">Dain Sundstrom</a>
41  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
42  * @version $Revision: 37459 $
43  */

44 public final class JDBCRelationshipRoleMetaData
45 {
46    /** Relation to which this role belongs. */
47    private final JDBCRelationMetaData relationMetaData;
48
49    /** Role name */
50    private final String JavaDoc relationshipRoleName;
51
52    /** Is the multiplicity one? If not, multiplicity is many. */
53    private final boolean multiplicityOne;
54
55    /** Should this role have a foreign key constraint? */
56    private final boolean foreignKeyConstraint;
57
58    /** Should this entity be deleted when related entity is deleted. */
59    private final boolean cascadeDelete;
60
61    /** Should the cascade-delete be batched. */
62    private final boolean batchCascadeDelete;
63
64    /** The entity that has this role. */
65    private final JDBCEntityMetaData entity;
66
67    /** Name of the entity's cmr field for this role. */
68    private final String JavaDoc cmrFieldName;
69
70    /** true if this side is navigable */
71    private final boolean navigable;
72
73    /** Type of the cmr field (i.e., collection or set) */
74    private final String JavaDoc cmrFieldType;
75
76    private boolean genIndex;
77
78    /** Type of the cmr field (i.e., collection or set) */
79    private final JDBCReadAheadMetaData readAhead;
80
81    /** The other role in this relationship. */
82    private JDBCRelationshipRoleMetaData relatedRole;
83
84    /** The key fields used by this role by field name. */
85    private Map JavaDoc keyFields;
86
87    public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData,
88                                        JDBCApplicationMetaData application,
89                                        RelationshipRoleMetaData role)
90       throws DeploymentException
91    {
92       this.relationMetaData = relationMetaData;
93
94       relationshipRoleName = role.getRelationshipRoleName();
95       multiplicityOne = role.isMultiplicityOne();
96       cascadeDelete = role.isCascadeDelete();
97       batchCascadeDelete = false;
98       foreignKeyConstraint = false;
99       readAhead = null;
100
101       String JavaDoc fieldName = loadCMRFieldName(role);
102       if(fieldName == null)
103       {
104          cmrFieldName = generateNonNavigableCMRName(role);
105          navigable = false;
106       }
107       else
108       {
109          cmrFieldName = fieldName;
110          navigable = true;
111       }
112       cmrFieldType = role.getCMRFieldType();
113
114       // get the entity for this role
115
entity = application.getBeanByEjbName(role.getEntityName());
116       if(entity == null)
117       {
118          throw new DeploymentException("Entity: " + role.getEntityName() +
119             " not found for relation: " + role.getRelationMetaData().getRelationName());
120       }
121    }
122
123    public JDBCRelationshipRoleMetaData(JDBCRelationMetaData relationMetaData,
124                                        JDBCApplicationMetaData application,
125                                        Element JavaDoc element,
126                                        JDBCRelationshipRoleMetaData defaultValues)
127       throws DeploymentException
128    {
129
130       this.relationMetaData = relationMetaData;
131       this.entity = application.getBeanByEjbName(defaultValues.getEntity().getName());
132
133       relationshipRoleName = defaultValues.getRelationshipRoleName();
134       multiplicityOne = defaultValues.isMultiplicityOne();
135       cascadeDelete = defaultValues.isCascadeDelete();
136
137       cmrFieldName = defaultValues.getCMRFieldName();
138       navigable = defaultValues.isNavigable();
139       cmrFieldType = defaultValues.getCMRFieldType();
140
141       // foreign key constraint? If not provided, keep default.
142
String JavaDoc fkString = MetaData.getOptionalChildContent(element, "fk-constraint");
143       if(fkString != null)
144       {
145          foreignKeyConstraint = Boolean.valueOf(fkString).booleanValue();
146       }
147       else
148       {
149          foreignKeyConstraint = defaultValues.hasForeignKeyConstraint();
150       }
151
152       // read-ahead
153
Element JavaDoc readAheadElement = MetaData.getOptionalChild(element, "read-ahead");
154       if(readAheadElement != null)
155       {
156          readAhead = new JDBCReadAheadMetaData(readAheadElement, entity.getReadAhead());
157       }
158       else
159       {
160          readAhead = entity.getReadAhead();
161       }
162
163       batchCascadeDelete = MetaData.getOptionalChild(element, "batch-cascade-delete") != null;
164       if(batchCascadeDelete)
165       {
166          if(!cascadeDelete)
167          throw new DeploymentException(
168             relationMetaData.getRelationName() + '/' + relationshipRoleName
169             + " has batch-cascade-delete in jbosscmp-jdbc.xml but has no cascade-delete in ejb-jar.xml"
170          );
171
172          if(relationMetaData.isTableMappingStyle())
173          {
174             throw new DeploymentException(
175                "Relationship " + relationMetaData.getRelationName()
176                + " with relation-table-mapping style was setup for batch cascade-delete."
177                + " Batch cascade-delete supported only for foreign key mapping style."
178             );
179          }
180       }
181    }
182
183    public void init(JDBCRelationshipRoleMetaData relatedRole)
184       throws DeploymentException
185    {
186       init(relatedRole, null);
187    }
188
189    public void init(JDBCRelationshipRoleMetaData relatedRole, Element JavaDoc element)
190       throws DeploymentException
191    {
192       this.relatedRole = relatedRole;
193       if(element == null || "defaults".equals(element.getTagName()))
194       {
195          keyFields = loadKeyFields();
196       }
197       else
198       {
199          keyFields = loadKeyFields(element);
200       }
201    }
202
203    private static String JavaDoc loadCMRFieldName(RelationshipRoleMetaData role)
204    {
205       return role.getCMRFieldName();
206    }
207
208    private static String JavaDoc generateNonNavigableCMRName(RelationshipRoleMetaData role)
209    {
210       RelationshipRoleMetaData relatedRole = role.getRelatedRoleMetaData();
211       return relatedRole.getEntityName() + "_" + relatedRole.getCMRFieldName();
212    }
213
214    /**
215     * Gets the relation to which this role belongs.
216     */

217    public JDBCRelationMetaData getRelationMetaData()
218    {
219       return relationMetaData;
220    }
221
222    /**
223     * Gets the name of this role.
224     */

225    public String JavaDoc getRelationshipRoleName()
226    {
227       return relationshipRoleName;
228    }
229
230    /**
231     * Should this role use a foreign key constraint.
232     * @return true if the store mananager will execute an ALTER TABLE ADD
233     * CONSTRAINT statement to add a foreign key constraint.
234     */

235    public boolean hasForeignKeyConstraint()
236    {
237       return foreignKeyConstraint;
238    }
239
240    /**
241     * Checks if the multiplicity is one.
242     */

243    public boolean isMultiplicityOne()
244    {
245       return multiplicityOne;
246    }
247
248    /**
249     * Checks if the multiplicity is many.
250     */

251    public boolean isMultiplicityMany()
252    {
253       return !multiplicityOne;
254    }
255
256    /**
257     * Should this entity be deleted when related entity is deleted.
258     */

259    public boolean isCascadeDelete()
260    {
261       return cascadeDelete;
262    }
263
264    public boolean isBatchCascadeDelete()
265    {
266       return batchCascadeDelete;
267    }
268
269    /**
270     * Gets the name of the entity that has this role.
271     */

272    public JDBCEntityMetaData getEntity()
273    {
274       return entity;
275    }
276
277    /**
278     * Gets the name of the entity's cmr field for this role.
279     */

280    public String JavaDoc getCMRFieldName()
281    {
282       return cmrFieldName;
283    }
284
285    private boolean isNavigable()
286    {
287       return navigable;
288    }
289
290    /**
291     * Gets the type of the cmr field (i.e., collection or set)
292     */

293    private String JavaDoc getCMRFieldType()
294    {
295       return cmrFieldType;
296    }
297
298    /**
299     * Gets the related role's jdbc meta data.
300     */

301    public JDBCRelationshipRoleMetaData getRelatedRole()
302    {
303       return relationMetaData.getOtherRelationshipRole(this);
304    }
305
306    /**
307     * Gets the read ahead meta data
308     */

309    public JDBCReadAheadMetaData getReadAhead()
310    {
311       return readAhead;
312    }
313
314    /**
315     * Gets the key fields of this role.
316     * @return an unmodifiable collection of JDBCCMPFieldMetaData objects
317     */

318    public Collection JavaDoc getKeyFields()
319    {
320       return Collections.unmodifiableCollection(keyFields.values());
321    }
322
323    public boolean isIndexed()
324    {
325       return genIndex;
326    }
327
328    /**
329     * Loads the key fields for this role based on the primary keys of the
330     * this entity.
331     */

332    private Map JavaDoc loadKeyFields()
333    {
334       // with foreign key mapping, foreign key fields are no added if
335
// - it is the many side of one-to-many relationship
336
// - it is the one side of one-to-one relationship and related side is not navigable
337
if(relationMetaData.isForeignKeyMappingStyle())
338       {
339          if(isMultiplicityMany())
340             return Collections.EMPTY_MAP;
341          else
342             if(getRelatedRole().isMultiplicityOne() && !getRelatedRole().isNavigable())
343                return Collections.EMPTY_MAP;
344       }
345
346       // get all of the pk fields
347
ArrayList JavaDoc pkFields = new ArrayList JavaDoc();
348       for(Iterator JavaDoc i = entity.getCMPFields().iterator(); i.hasNext();)
349       {
350          JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) i.next();
351          if(cmpField.isPrimaryKeyMember())
352          {
353             pkFields.add(cmpField);
354          }
355       }
356
357       // generate a new key field for each pk field
358
Map JavaDoc fields = new HashMap JavaDoc(pkFields.size());
359       for(Iterator JavaDoc i = pkFields.iterator(); i.hasNext();)
360       {
361          JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) i.next();
362
363          String JavaDoc columnName;
364          if(relationMetaData.isTableMappingStyle())
365          {
366             if(entity.equals(relatedRole.getEntity()))
367                columnName = getCMRFieldName();
368             else
369                columnName = entity.getName();
370          }
371          else
372          {
373             columnName = relatedRole.getCMRFieldName();
374          }
375
376          if(pkFields.size() > 1)
377          {
378             columnName += "_" + cmpField.getFieldName();
379          }
380
381          cmpField = new JDBCCMPFieldMetaData(
382             entity,
383             cmpField,
384             columnName,
385             false,
386             relationMetaData.isTableMappingStyle(),
387             relationMetaData.isReadOnly(),
388             relationMetaData.getReadTimeOut(),
389             relationMetaData.isTableMappingStyle());
390          fields.put(cmpField.getFieldName(), cmpField);
391       }
392       return Collections.unmodifiableMap(fields);
393    }
394
395    /**
396     * Loads the key fields for this role based on the primary keys of the
397     * this entity and the override data from the xml element.
398     */

399    private Map JavaDoc loadKeyFields(Element JavaDoc element)
400       throws DeploymentException
401    {
402       Element JavaDoc keysElement = MetaData.getOptionalChild(element, "key-fields");
403
404       // no field overrides, we're done
405
if(keysElement == null)
406       {
407          return loadKeyFields();
408       }
409
410       // load overrides
411
Iterator JavaDoc iter = MetaData.getChildrenByTagName(keysElement, "key-field");
412
413       // if key-fields element empty, no key should be used
414
if(!iter.hasNext())
415       {
416          return Collections.EMPTY_MAP;
417       }
418       else
419          if(relationMetaData.isForeignKeyMappingStyle() && isMultiplicityMany())
420          {
421             throw new DeploymentException("Role: " + relationshipRoleName + " with multiplicity many using " +
422                "foreign-key mapping is not allowed to have key-fields");
423          }
424
425       // load the default field values
426
Map JavaDoc defaultFields = getPrimaryKeyFields();
427
428       // load overrides
429
Map JavaDoc fields = new HashMap JavaDoc(defaultFields.size());
430       while(iter.hasNext())
431       {
432          Element JavaDoc keyElement = (Element JavaDoc) iter.next();
433          String JavaDoc fieldName = MetaData.getUniqueChildContent(keyElement, "field-name");
434
435          JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) defaultFields.remove(fieldName);
436          if(cmpField == null)
437          {
438             throw new DeploymentException(
439                "Role '" + relationshipRoleName + "' on Entity Bean '" +
440                entity.getName() + "' : CMP field for key not found: field " +
441                "name='" + fieldName + "'");
442          }
443          String JavaDoc isIndexedtmp = MetaData.getOptionalChildContent(keyElement, "dbindex");
444          boolean isIndexed;
445
446          if(isIndexedtmp != null)
447             isIndexed = true;
448          else
449             isIndexed = false;
450          genIndex = isIndexed;
451
452
453          cmpField = new JDBCCMPFieldMetaData(
454             entity,
455             keyElement,
456             cmpField,
457             false,
458             relationMetaData.isTableMappingStyle(),
459             relationMetaData.isReadOnly(),
460             relationMetaData.getReadTimeOut(),
461             relationMetaData.isTableMappingStyle());
462          fields.put(cmpField.getFieldName(), cmpField);
463       }
464
465       // all fields must be overriden
466
if(!defaultFields.isEmpty())
467       {
468          throw new DeploymentException("Mappings were not provided for all " +
469             "fields: unmaped fields=" + defaultFields.keySet() +
470             " in role=" + relationshipRoleName);
471       }
472       return Collections.unmodifiableMap(fields);
473    }
474
475    /**
476     * Returns the primary key fields of the entity mapped by field name.
477     */

478    private Map JavaDoc getPrimaryKeyFields()
479    {
480       Map JavaDoc pkFields = new HashMap JavaDoc();
481       for(Iterator JavaDoc cmpFieldsIter = entity.getCMPFields().iterator(); cmpFieldsIter.hasNext();)
482       {
483          JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) cmpFieldsIter.next();
484          if(cmpField.isPrimaryKeyMember())
485             pkFields.put(cmpField.getFieldName(), cmpField);
486       }
487       return pkFields;
488    }
489 }
490
Popular Tags