From: Vance K. <va...@us...> - 2007-06-30 03:53:47
|
User: vancek Date: 07/06/29 20:53:48 Modified: andromda-ejb3/src/site changes.xml andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades EJB3AssociationFacadeLogicImpl.java EJB3MetafacadeUtils.java andromda-ejb3/src/test/expected cartridge-output.zip andromda-ejb3/src/test/uml EJB3CartridgeTestModel.xml.zip andromda-ejb3/src/main/resources/templates/ejb3 EntityEmbeddable.vsl andromda-ejb3/src/site/axdoc howto.xml howto2.xml Log: ejb-50 - add join table for one-to-many unidirectional associations Revision Changes Path 1.24 +17 -1 cartridges/andromda-ejb3/src/site/changes.xml Index: changes.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/changes.xml,v retrieving revision 1.23 retrieving revision 1.24 diff -u -w -r1.23 -r1.24 --- changes.xml 23 Jun 2007 09:07:35 -0000 1.23 +++ changes.xml 30 Jun 2007 03:53:47 -0000 1.24 @@ -484,11 +484,27 @@ <action dev="vancek" due-to="heapifyman" type="add"> JIRA EJB-56 - Add support for multiplicity on enumeration types. </action> - <action dev="vancek" tue-to="mrkanban" type="fix"> + <action dev="vancek" due-to="mrkanban" type="fix"> When a child entity inherits from a mapped superclass and the child entity has an implementation, the child mapped superclass did not extend the parent mapped superclass correctly. This was a side-effect of applying EJB-53. </action> + <action dev="vancek" due-to="darquerus " type="add"> + JIRA EJB-59 - Add support for setting the join table for unidirectional one-to-many associations. Currently, + this exists for many-to-many associations using the JoinTable annotation. + Existing users must be aware that this will change the default behaviour of the cartridge for the join + table name. The EJB 3.0 spec defines the join table name with the owning side first and underscore + separated. AndroMDA (not the EJB3 cartridge) defines the inverse end first with a digit two (2) as the + separater and truncates the name by the specified length in the andromda.xml namespace property + maxSqlNameLength. Prior to this change (lack of a JoinTable annotation), the EJB 3.0 default name was + used for one-to-many associations and the AndroMDA naming convention was used for many-to-many associations. + We are now adopting the the EJB 3.0 naming convention for join table names for both association types. + To avoid recreation of join tables for existing many-to-many associations, you have the choice of specifying + the @andromda.persistence.table tagged value on the specific associations or setting the association name + to correspond to the join table. You should also define the namespace property + relationNameSeparator in the andromda.xml within the ejb3 namespace with a value of underscore (_) if you + wish to adopt this separator. The default separator will remain the AndroMDA default digit two. + </action> </release> </body> </document> \ No newline at end of file 1.5 +96 -4 cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3AssociationFacadeLogicImpl.java Index: EJB3AssociationFacadeLogicImpl.java =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3AssociationFacadeLogicImpl.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -w -r1.4 -r1.5 --- EJB3AssociationFacadeLogicImpl.java 17 Jan 2007 00:50:55 -0000 1.4 +++ EJB3AssociationFacadeLogicImpl.java 30 Jun 2007 03:53:47 -0000 1.5 @@ -1,5 +1,18 @@ package org.andromda.cartridges.ejb3.metafacades; +import java.util.Collection; +import java.util.Iterator; + +import org.andromda.metafacades.uml.AssociationEndFacade; +import org.andromda.metafacades.uml.Entity; +import org.andromda.metafacades.uml.EntityMetafacadeUtils; +import org.andromda.metafacades.uml.MetafacadeUtils; +import org.andromda.metafacades.uml.ModelElementFacade; +import org.andromda.metafacades.uml.UMLMetafacadeProperties; +import org.andromda.metafacades.uml.UMLProfile; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; + /** * MetafacadeLogic implementation for org.andromda.cartridges.ejb3.metafacades.EJB3AssociationFacade. * @@ -19,15 +32,94 @@ // --------------- methods --------------------- /** + * Override to provide support for One-2-Many unidirectional associations as well as Many-2-Many. + * * Returns the EJB3 cartridge specific table name for the association */ public String getTableName() { - String tableName = super.getTableName(); - if (getName().toLowerCase().startsWith(tableName.toLowerCase())) + String tableName = null; + final Collection ends = this.getAssociationEnds(); + if (ends != null && !ends.isEmpty()) + { + for (Iterator iterator = ends.iterator(); iterator.hasNext();) { - tableName = getRelationName().replaceAll("-", "_").toUpperCase(); + final EJB3AssociationEndFacade end = (EJB3AssociationEndFacade)iterator.next(); + if ((end.isMany2Many() && end.isOwning()) || + (end.isOne2Many() && !end.isNavigable() && end.getOtherEnd().isNavigable())) + { + // prevent ClassCastException if the association isn't an + // Entity + if (Entity.class.isAssignableFrom(end.getType().getClass())) + { + final String prefixProperty = UMLMetafacadeProperties.TABLE_NAME_PREFIX; + final String tableNamePrefix = + this.isConfiguredProperty(prefixProperty) + ? ObjectUtils.toString(this.getConfiguredProperty(prefixProperty)) : null; + tableName = + EJB3MetafacadeUtils.getSqlNameFromTaggedValue( + tableNamePrefix, + this, + UMLProfile.TAGGEDVALUE_PERSISTENCE_TABLE, + ((Entity)end.getType()).getMaxSqlNameLength(), + null, + this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR)); + } + break; + } } + } + +// if (StringUtils.isNotBlank(tableName) && getName().toLowerCase().startsWith(tableName.toLowerCase())) +// { +// tableName = getRelationName().replaceAll("-", "_").toUpperCase(); +// } + return tableName; } + + /** + * Override the default implementation to use the current getRelationName implementation + */ + public String getName() + { + String name = (super.getName().equalsIgnoreCase(super.getRelationName()) ? null : super.getName()); + + // if the name isn't defined, use the this implementation of relation name + if (StringUtils.isEmpty(name)) + { + name = this.getRelationName(); + } + return name; + } + + /** + * Override the default implementation to set the owning side name first followed by inverse side. + * If there is no owning side defined, then adopt the default logic of using alphabetical ordering. + */ + public String getRelationName() + { + final Collection ends = this.getAssociationEnds(); + final Iterator endIt = ends.iterator(); + final EJB3AssociationEndFacade firstEnd = (EJB3AssociationEndFacade)endIt.next(); + final EJB3AssociationEndFacade secondEnd = (EJB3AssociationEndFacade)endIt.next(); + final String separator = String.valueOf( + this.getConfiguredProperty(UMLMetafacadeProperties.RELATION_NAME_SEPARATOR)); + + if (secondEnd.isOwning()) + { + return secondEnd.getName() + separator + firstEnd.getName(); + } + else if (firstEnd.isOwning()) + { + return firstEnd.getName() + separator + secondEnd.getName(); + } + else + { + return MetafacadeUtils.toRelationName( + firstEnd.getName(), + secondEnd.getName(), + separator); + } + } } \ No newline at end of file 1.11 +65 -0 cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3MetafacadeUtils.java Index: EJB3MetafacadeUtils.java =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/main/java/org/andromda/cartridges/ejb3/metafacades/EJB3MetafacadeUtils.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -w -r1.10 -r1.11 --- EJB3MetafacadeUtils.java 16 Apr 2007 14:09:41 -0000 1.10 +++ EJB3MetafacadeUtils.java 30 Jun 2007 03:53:47 -0000 1.11 @@ -5,6 +5,7 @@ import org.andromda.core.common.ExceptionUtils; import org.andromda.metafacades.uml.AttributeFacade; import org.andromda.metafacades.uml.ClassifierFacade; +import org.andromda.metafacades.uml.EntityMetafacadeUtils; import org.andromda.metafacades.uml.ModelElementFacade; import org.andromda.metafacades.uml.OperationFacade; import org.andromda.metafacades.uml.UMLProfile; @@ -504,4 +505,68 @@ return buf.toString(); } } + + /** + * Gets the SQL name. (i.e. column name, table name, etc.). If it can't find + * the corresponding tagged value with the specified <code>name</code>, + * then it uses the element name by default and just returns that. + * + * @param prefix the optional prefix to add to the sql name (i.e. table name + * prefix, etc.). + * @param element from which to retrieve the SQL name. + * @param name the name of the tagged value. + * @param nameMaxLength if this is not null, then the name returned will be + * trimmed to this length (if it happens to be longer). + * @param suffix the optional suffix to add to the sql name (i.e. foreign + * key suffix, etc.) + * @param separator character used to separate words + * @return the SQL name as a String. + */ + public static String getSqlNameFromTaggedValue( + String prefix, + final EJB3AssociationFacade element, + String name, + final Short nameMaxLength, + String suffix, + final Object separator) + { + if (element != null) + { + Object value = element.findTaggedValue(name); + StringBuffer buffer = new StringBuffer(StringUtils.trimToEmpty((String)value)); + if (StringUtils.isEmpty(buffer.toString())) + { + // if we can't find the tagValue then use the + // element name for the name + buffer = new StringBuffer( + EntityMetafacadeUtils.toSqlName( + element.getName(), + separator)); + + suffix = StringUtils.trimToEmpty(suffix); + prefix = StringUtils.trimToEmpty(prefix); + if (nameMaxLength != null) + { + final short maxLength = (short)(nameMaxLength.shortValue() - suffix.length() - prefix.length()); + buffer = + new StringBuffer( + EntityMetafacadeUtils.ensureMaximumNameLength( + buffer.toString(), + new Short(maxLength))); + } + if (StringUtils.isNotBlank(prefix)) + { + buffer.insert( + 0, + prefix); + } + if (StringUtils.isNotBlank(suffix)) + { + buffer.append(suffix); + } + } + name = buffer.toString(); + } + return name; + } } \ No newline at end of file 1.14 +499 -492 cartridges/andromda-ejb3/src/test/expected/cartridge-output.zip <<Binary file>> 1.9 +249 -258 cartridges/andromda-ejb3/src/test/uml/EJB3CartridgeTestModel.xml.zip <<Binary file>> 1.54 +7 -0 cartridges/andromda-ejb3/src/main/resources/templates/ejb3/EntityEmbeddable.vsl Index: EntityEmbeddable.vsl =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/main/resources/templates/ejb3/EntityEmbeddable.vsl,v retrieving revision 1.53 retrieving revision 1.54 diff -u -w -r1.53 -r1.54 --- EntityEmbeddable.vsl 23 Jun 2007 09:07:36 -0000 1.53 +++ EntityEmbeddable.vsl 30 Jun 2007 03:53:48 -0000 1.54 @@ -628,6 +628,13 @@ #* *##else @javax.persistence.OneToMany(#if ($target.cascadeType)cascade = {${target.cascadeType}}#set ($argExists = true)#end#if ($associationEnd.navigable)#if ($argExists) ,#end#**#mappedBy = "${associationEnd.name}"#set ($argExists = true)#end#if ($target.eager)#if ($argExists), #end#**#fetch = javax.persistence.FetchType.EAGER#end) #* *##end +## +## Set the JointTable annotation to limit the association table name length. +## This is only set if the relationship is unidirectional. +## +#* *##if (!$associationEnd.navigable && $target.navigable) + @javax.persistence.JoinTable(name = "${associationEnd.association.tableName}") +#* *##end #* *##if ($target.map) @javax.persistence.MapKey#if ($target.hasTaggedValue("@andromda.persistence.collection.index"))(name = "${target.collectionIndexName}")#end 1.5 +1 -1 cartridges/andromda-ejb3/src/site/axdoc/howto.xml Index: howto.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/axdoc/howto.xml,v retrieving revision 1.4 retrieving revision 1.5 diff -u -w -r1.4 -r1.5 --- howto.xml 4 Feb 2007 04:18:18 -0000 1.4 +++ howto.xml 30 Jun 2007 03:53:48 -0000 1.5 @@ -67,7 +67,7 @@ <li><a href="howto2.html#Cascading">Cascading</a></li> <li><a href="howto2.html#Fetch_Type">Fetch Type</a></li> <li><a href="howto2.html#Ordering_Collection_Valued_Association">Ordering Collection Valued Association</a></li> - <li><a href="howto2.html#Join_Table_Many_To_Many">Join Table for Many-To-Many Relationship</a></li> + <li><a href="howto2.html#Join_Table_Many_To_Many_And_One_To_Many">Join Table for Many-To-Many and One-To-Many Relationships</a></li> <li><a href="howto2.html#Aggregation_Composition">Aggregation and Composition</a></li> <li><a href="howto2.html#Transient_Relationships">Transient Relationships</a></li> <li><a href="howto2.html#Tips">Tips</a></li> 1.4 +20 -7 cartridges/andromda-ejb3/src/site/axdoc/howto2.xml Index: howto2.xml =================================================================== RCS file: /cvsroot/andromdaplugins/cartridges/andromda-ejb3/src/site/axdoc/howto2.xml,v retrieving revision 1.3 retrieving revision 1.4 diff -u -w -r1.3 -r1.4 --- howto2.xml 7 May 2007 13:50:26 -0000 1.3 +++ howto2.xml 30 Jun 2007 03:53:48 -0000 1.4 @@ -264,18 +264,31 @@ </ul> </p> </subsection> - <a name="Join_Table_Many_To_Many"/> - <subsection name="Join Table for Many-To-Many Relationship"> + <a name="Join_Table_Many_To_Many_And_One_To_Many"/> + <subsection name="Join Table for Many-To-Many and One-To-Many Relationship"> <p> - For a Many-To-Many association, the <code>@javax.persistence.JoinTable</code> annotation - is specified on the OWNING side of the association. This is determined by modelling the + For a Many-To-Many and now One-To-Many association, the <code>@javax.persistence.JoinTable</code> + annotation is specified on the OWNING side of the association. This is determined by modeling the <code>owning</code> side as an aggregation or composition. </p> <p> - The join table name is defined by default to be the table name of the primary table of owning + If there is no owning side defined, then the AndroMDA default convention of + an alphabetical name ordering is adopted. + </p> + <p> + The join table name is defined by default to be the table name of the primary table of the owning side concatenated with the table name of the primary table of the inverse side. - You can override the <code>name</code> property by modelling the - <code>@andromda.persistence.table</code> tagged value on the assocation. + You can override the <code>name</code> property by modeling the + <code>@andromda.persistence.table</code> tagged value on the assocation or alternatively, + specify a name for the association. + </p> + <p> + The default relation name separator is adopted from the AndroMDA metafacade namespace layer. + You can simply change this in your application's andromda.xml by specifying the following + property in the <b>ejb3</b> namespace. +<source language="java"><![CDATA[ + <property name="relationNameSeparator">_</property> +]]></source> </p> </subsection> <a name="Aggregation_Composition"/> |