001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: EjbRelationshipRoleDesc.java 6673 2005-04-28 16:53:00Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.deployment.api;
025:
026: import java.util.HashMap;
027: import java.util.Iterator;
028:
029: import org.objectweb.jonas_ejb.deployment.xml.EjbRelationshipRole;
030: import org.objectweb.jonas_ejb.deployment.xml.ForeignKeyJdbcMapping;
031: import org.objectweb.jonas_ejb.deployment.xml.JonasEjbRelationshipRole;
032: import org.objectweb.jonas_lib.deployment.api.DeploymentDescException;
033: import org.objectweb.util.monolog.api.BasicLevel;
034: import org.objectweb.util.monolog.api.Logger;
035:
036: /**
037: * Class to hold meta-information related to an ejb-relation-role
038: * Created on July 7, 2002
039: * @author Christophe Ney [cney@batisseurs.com] : Initial developer
040: * @author Helene Joanin on May 2003: code cleanup
041: * @author Helene Joanin on May 2003: complement for legacy first version
042: */
043: public class EjbRelationshipRoleDesc {
044:
045: private Logger logger = null;
046:
047: /**
048: * This constant can be used to represent an index of a gen class.
049: */
050: public static final byte INDEX = 1;
051:
052: /**
053: * This constant can be used to represent the source of the relation, ie the
054: * element which references the other.
055: */
056: public static final byte SOURCE = 2;
057:
058: /**
059: * This constant can be used to represent the target of the relation, ie the
060: * element which is referenced by the other.
061: */
062: public static final byte TARGET = 4;
063:
064: /**
065: * Don't change these values without looking at getRelationType() !
066: */
067: public static final byte OOU = 0;
068:
069: public static final byte OOB = 1;
070:
071: public static final byte OMU = 2;
072:
073: public static final byte OMB = OMU + OOB;
074:
075: public static final byte MOU = 4;
076:
077: public static final byte MOB = MOU + OOB;
078:
079: public static final byte MMU = OMU + MOU;
080:
081: public static final byte MMB = MMU + OOB;
082:
083: private String rsrName;
084:
085: private String ejbSourceName;
086:
087: private EjbRelationDesc ejbRelationDesc;
088:
089: private EntityCmp2Desc sourceEntityCmp2Desc;
090:
091: private boolean isSourceMultiple;
092:
093: private EntityCmp2Desc targetEntityCmp2Desc;
094:
095: private boolean isTargetMultiple;
096:
097: private boolean isSlave;
098:
099: protected String cmrFieldName = null;
100:
101: protected Class cmrFieldType = null;
102:
103: protected boolean isJOnASCMR = false;
104:
105: private byte relationType = -1;
106:
107: private boolean mustCascade;
108:
109: // Zeus objects for the associated mapping information (needed in
110: // fillMappingInfo);
111: // They may be null.
112: private JonasEjbRelationshipRole jSourceRsRole = null;
113:
114: // mapping information build by fillMappingInfo and
115: // fillMappingInfoWithDefault
116: private HashMap foreignKeyMap = new HashMap();
117:
118: private boolean hasJdbcMapping = false;
119:
120: /**
121: * constructor to be used by parent node
122: * @param rd parent node = EjbRelationDesc
123: * @param role this role (standard EjbRelationshipRole)
124: * @param jrole this Jonas role (JonasEjbRelationshipRole). This param may
125: * be null.
126: * @param opposite opposite role in the relation (standard
127: * EjbRelationshipRole)
128: * @throws DeploymentDescException in error case.
129: */
130: public EjbRelationshipRoleDesc(EjbRelationDesc rd, String name,
131: EjbRelationshipRole role, JonasEjbRelationshipRole jrole,
132: EjbRelationshipRole opposite, boolean isSlave, Logger logger)
133: throws DeploymentDescException {
134:
135: this .logger = logger;
136: ejbRelationDesc = rd;
137: this .isSlave = isSlave;
138: rsrName = name;
139: mustCascade = opposite.isCascadeDelete();
140: ejbSourceName = role.getRelationshipRoleSource().getEjbName();
141:
142: // mutiplicity is One or Many
143: if (opposite.getMultiplicity().equalsIgnoreCase("Many")) {
144: isTargetMultiple = true;
145: if (role.isCascadeDelete()) {
146: throw new DeploymentDescException(
147: "Cascade delete not allowed for relationshipRole for relationship '"
148: + rd.getName()
149: + "(because opposite role has a multiplicity of Many)");
150: }
151: } else if (opposite.getMultiplicity().equalsIgnoreCase("One")) {
152: isTargetMultiple = false;
153: } else {
154: throw new DeploymentDescException(
155: "Invalid multiplicity value for relationshipRole for relationship '"
156: + rd.getName() + "'(must be One or Many)");
157: }
158: if (role.getMultiplicity().equalsIgnoreCase("Many")) {
159: isSourceMultiple = true;
160: } else if (role.getMultiplicity().equalsIgnoreCase("One")) {
161: isSourceMultiple = false;
162: } else {
163: throw new DeploymentDescException(
164: "Invalid multiplicity value for relationshipRole for relationship '"
165: + rd.getName() + "'(must be One or Many)");
166: }
167:
168: // store cmr field if any
169: if (role.getCmrField() != null) {
170: setCmrFieldName(role.getCmrField().getCmrFieldName());
171: if (isTargetMultiple) {
172: String type = role.getCmrField().getCmrFieldType();
173: if (type == null) {
174: throw new DeploymentDescException(
175: "You must specify a cmr-field-type in case where the relation is 'Many' in the cmr-field '"
176: + cmrFieldName
177: + "' of bean "
178: + ejbSourceName);
179: }
180: setCmrFieldType(type);
181: }
182: }
183:
184: // store the JonasEjbRelationshipRole
185: jSourceRsRole = jrole;
186: }
187:
188: /**
189: * Fills the mapping information of this relation-ship role with the values
190: * defined in jonas DD.
191: * @throws DeploymentDescException in error case.
192: */
193: protected void fillMappingInfo() throws DeploymentDescException {
194: if (logger.isLoggable(BasicLevel.DEBUG)) {
195: logger.log(BasicLevel.DEBUG, "" + (jSourceRsRole != null)
196: + " for " + rsrName);
197: }
198: if (jSourceRsRole != null) {
199: for (Iterator i = jSourceRsRole
200: .getForeignKeyJdbcMappingList().iterator(); i
201: .hasNext();) {
202: ForeignKeyJdbcMapping fkMapping = (ForeignKeyJdbcMapping) i
203: .next();
204: String fkc = fkMapping.getForeignKeyJdbcName();
205: String kc = null;
206: if (fkMapping.getKeyJdbcName() != null) {
207: kc = fkMapping.getKeyJdbcName();
208: }
209: if (kc == null) {
210: // if the target bean has a primary-key-field, this value
211: // may not be defined
212: // in this case, this is the column name of the
213: // primary-key-field
214: if (targetEntityCmp2Desc.hasSimplePkField()) {
215: kc = ((FieldJdbcDesc) targetEntityCmp2Desc
216: .getSimplePkField()).getJdbcFieldName();
217: } else {
218: // error
219: throw new DeploymentDescException(
220: "key-jdbc-name must be provided for foreign-key-jdbc-mapping "
221: + fkc
222: + " of relation-ship role "
223: + rsrName + "of relation "
224: + ejbRelationDesc.getName());
225: }
226: }
227: if (logger.isLoggable(BasicLevel.DEBUG)) {
228: logger.log(BasicLevel.DEBUG,
229: "explicit fk mapping = " + fkc + " for "
230: + kc);
231: }
232: foreignKeyMap.put(kc, fkc);
233: }
234: hasJdbcMapping = true;
235: }
236: }
237:
238: /**
239: * Fills the mapping information of this relation-ship role with default
240: * values if the mapping information is not already initialized.
241: */
242: protected void fillMappingInfoWithDefault() {
243: if (logger.isLoggable(BasicLevel.DEBUG)) {
244: logger.log(BasicLevel.DEBUG, "" + hasJdbcMapping);
245: }
246: if (!hasJdbcMapping) {
247: if (targetEntityCmp2Desc.hasSimplePkField()) {
248: // target entity has a simple pk (primary-key-field)
249: String fn = targetEntityCmp2Desc.getSimplePkFieldName();
250: FieldJdbcDesc fd = (FieldJdbcDesc) targetEntityCmp2Desc
251: .getCmpFieldDesc(fn);
252: String kc = fd.getJdbcFieldName();
253: String fkc = targetEntityCmp2Desc
254: .getAbstractSchemaName()
255: + "_" + kc;
256: if (logger.isLoggable(BasicLevel.DEBUG)) {
257: logger.log(BasicLevel.DEBUG,
258: "default fk mapping = " + fkc + " for "
259: + kc);
260: }
261: foreignKeyMap.put(kc, fkc);
262: } else {
263: // target entity has a composite pk
264: for (Iterator i = targetEntityCmp2Desc
265: .getCmpFieldDescIterator(); i.hasNext();) {
266: FieldJdbcDesc fd = (FieldJdbcDesc) i.next();
267: String kc = fd.getJdbcFieldName();
268: String fkc = targetEntityCmp2Desc
269: .getAbstractSchemaName()
270: + "_" + kc;
271: if (logger.isLoggable(BasicLevel.DEBUG)) {
272: logger.log(BasicLevel.DEBUG,
273: "default fk mapping = " + fkc + " for "
274: + kc);
275: }
276: foreignKeyMap.put(kc, fkc);
277: }
278: }
279: hasJdbcMapping = true;
280: }
281: }
282:
283: /**
284: * return the name of this relationship role.
285: * @return the String name of this relationship role.
286: */
287: public String getName() {
288: return rsrName;
289: }
290:
291: protected void setCmrFieldName(String name)
292: throws DeploymentDescException {
293: cmrFieldName = name;
294: }
295:
296: protected void setCmrFieldType(String type)
297: throws DeploymentDescException {
298: try {
299: cmrFieldType = Class.forName(type);
300: } catch (ClassNotFoundException e) {
301: throw new DeploymentDescException(
302: "class name not found for cmr-field "
303: + cmrFieldName + " of bean "
304: + ejbSourceName, e);
305: }
306: if (!(cmrFieldType.getName().equals("java.util.Collection") || cmrFieldType
307: .getName().equals("java.util.Set"))) {
308: throw new DeploymentDescException(
309: "value of cmr-field-type "
310: + cmrFieldName
311: + " of bean "
312: + ejbSourceName
313: + " should be java.util.Set or java.util.Collection if set");
314: }
315: }
316:
317: /**
318: * mark the cmr as added by JOnAS
319: */
320: protected void setIsJOnASCmrField() {
321: isJOnASCMR = true;
322: }
323:
324: /**
325: * set the source bean of this relation-ship role.
326: * @param led EntityCmp2Desc for the source bean of this relation-ship role.
327: */
328: protected void setSourceBean(EntityCmp2Desc led) {
329: sourceEntityCmp2Desc = led;
330: }
331:
332: /**
333: * set the target bean of this relation-ship role.
334: * @param led EntityCmp2Desc for the target bean of this relation-ship role.
335: */
336: protected void setTargetBean(EntityCmp2Desc led) {
337: targetEntityCmp2Desc = led;
338: if (cmrFieldType == null) {
339: cmrFieldType = led.getLocalClass();
340: }
341: }
342:
343: /**
344: * get the parent ejb relation of this relation-ship-role.
345: * @return the EjbRelationDesc of this relation-ship-role.
346: */
347: public EjbRelationDesc getRelation() {
348: return ejbRelationDesc;
349: }
350:
351: /**
352: * get the opposite relation-ship-role of this relation-ship-role.
353: * @return the opposite EjbRelationshipRoleDesc of this relation-ship-role.
354: */
355: public EjbRelationshipRoleDesc getOppositeRelationshipRole() {
356: EjbRelationshipRoleDesc res = ejbRelationDesc
357: .getRelationshipRole1();
358: if (res == this ) {
359: return ejbRelationDesc.getRelationshipRole2();
360: } else {
361: return res;
362: }
363: }
364:
365: /**
366: * Get the name of the ejb involved in this relation-ship-role. This is the
367: * source bean name of this relation.
368: * @return the String ejb-name of the source bean.
369: */
370: public String getSourceBeanName() {
371: return ejbSourceName;
372: }
373:
374: /**
375: * Get the ejb involved in this relation-ship-role. this is the source bean
376: * of this relation.
377: * @return the EntityCmp2Desc of the source bean.
378: */
379: public EntityCmp2Desc getSourceBean() {
380: return sourceEntityCmp2Desc;
381: }
382:
383: /**
384: * It retrieves the EntityCmp2Desc which is linked to the EntityCmp2Desc
385: * associated to this EjbRelationshipRoleDesc. This is the target bean of
386: * this relationship role
387: * @return the EntityCmp2Desc of the target bean.
388: */
389: public EntityCmp2Desc getTargetBean() {
390: return targetEntityCmp2Desc;
391: }
392:
393: /**
394: * Get state of opposite relationship-role is relation multiple.
395: * @return true if the opposite relationship-role is relation multiple.
396: */
397: public boolean isSourceMultiple() {
398: return isSourceMultiple;
399: }
400:
401: /**
402: * Get state of this relationship-role is relation multiple. (get state of
403: * field is relation multiple).
404: * @return true if the relationship-role is relation multiple.
405: */
406: public boolean isTargetMultiple() {
407: return isTargetMultiple;
408: }
409:
410: /**
411: * @return true if this bean must cascade delete the other bean in this
412: * relation.
413: */
414: public boolean mustCascade() {
415: return mustCascade;
416: }
417:
418: /**
419: * It returns a boolean value which indicates if the cmr has been added by
420: * JOnAS (true) or if the user has specified a cmr field in the descriptor.
421: * A CMR field is be added to manage the coherence of the relation OXu
422: * @return true if the CMR field is not a bean's programmer CMR field.
423: */
424: public boolean isJOnASCmrField() {
425: return isJOnASCMR;
426: }
427:
428: /**
429: * It retrieves true if the EntityCmp2Desc associated to this
430: * EjbRelationshipRoleDesc has a cmr field to the linked EntityCmp2Desc
431: * @return true if the relation-ship-role has a CMR field.
432: */
433: // TODO: is this method really needed (return always true??)
434: public boolean hasCmrField() {
435: return cmrFieldName != null;
436: }
437:
438: /**
439: * get the name of the cmr-field.
440: * @return the String name of the cmr-field.
441: */
442: public String getCmrFieldName() {
443: return cmrFieldName;
444: }
445:
446: /**
447: * get the type of the cmr-field when set in the deployment descriptor.
448: * @return Collection or Set for multiple rel. and null for non multiple
449: * rel.
450: */
451: public Class getCmrFieldType() {
452: return cmrFieldType;
453: }
454:
455: /**
456: * This method depends on static values OOB,OOU,... defined upper !
457: * @return the type of the relation: OO-u, OO-b, OM-u, ....
458: */
459: public byte getRelationType() {
460: if (relationType == -1) {
461: relationType = OOU;
462: EjbRelationshipRoleDesc rsr2 = getOppositeRelationshipRole();
463: if (rsr2.hasCmrField() && hasCmrField()) {
464: relationType += OOB;
465: }
466: if (isTargetMultiple()) {
467: relationType += OMU;
468: }
469: if (rsr2.isTargetMultiple()) {
470: relationType += MOU;
471: }
472: }
473: return relationType;
474: }
475:
476: /**
477: * Is a jdbc mapping is defined for this relationship role ?
478: * @return true if a jdbc mapping is defined for this relationship role.
479: */
480: public boolean hasJdbcMapping() {
481: return hasJdbcMapping;
482: }
483:
484: /**
485: * In M-N relationships, only 1 role will write data on DB.
486: * @return true if role will not write MN relations on database
487: */
488: public boolean isSlave() {
489: return isSlave;
490: }
491:
492: /**
493: * @param jdbcFieldName a primary key column name of the table associated to
494: * the target bean.
495: * @return the foreign key column name associated to the given primary key
496: * column name.
497: */
498: public String getForeignKeyJdbcName(String jdbcFieldName) {
499: return (String) foreignKeyMap.get(jdbcFieldName);
500: }
501:
502: /**
503: * String representation of the object for test purpose
504: * @return String representation of this object
505: */
506: public String toString() {
507: StringBuffer ret = new StringBuffer();
508: ret.append("\ngetName() = " + getName());
509: ret.append("\ngetRelation().getName() = "
510: + getRelation().getName());
511: ret.append("\ngetOppositeRelationshipRole().getName() = "
512: + getOppositeRelationshipRole().getName());
513: ret.append("\ngetSourceBeanName() = " + getSourceBeanName());
514: ret.append("\ngetTargetBean().getName() = "
515: + getTargetBean().getEjbName());
516: ret.append("\nisSourceMultiple() = " + isSourceMultiple());
517: ret.append("\nisTargetMultiple() = " + isTargetMultiple());
518: ret.append("\nmustCascade() = " + mustCascade());
519: ret.append("\nisJOnASCmrField() = " + isJOnASCmrField());
520: ret.append("\ngetCmrFieldName() = " + getCmrFieldName());
521: ret.append("\ngetCmrFieldType() = " + getCmrFieldType());
522: ret.append("\ngetRelationType() = " + getRelationType());
523: if (hasJdbcMapping()) {
524: for (Iterator i = foreignKeyMap.keySet().iterator(); i
525: .hasNext();) {
526: String key = (String) i.next();
527: String fkey = (String) foreignKeyMap.get(key);
528: ret.append("\ngetForeignKeyJdbcName(" + key + ")="
529: + fkey);
530: }
531: }
532: return ret.toString();
533: }
534:
535: }
|