/** * <copyright> * * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Martin Taal * </copyright> * * $Id: BidirectionalManyToManyAnnotator.java,v 1.8 2008/05/27 07:42:10 mtaal Exp $ */ package org.eclipse.emf.teneo.annotations.mapper; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference; import org.eclipse.emf.teneo.annotations.pannotation.JoinTable; import org.eclipse.emf.teneo.annotations.pannotation.ManyToMany; import org.eclipse.emf.teneo.extension.ExtensionPoint; /** * Annotates a bidirectional many-to-many ereference. * * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> * @version $Revision: 1.8 $ */ public class BidirectionalManyToManyAnnotator extends BaseEFeatureAnnotator implements ExtensionPoint { // The logger protected static final Log log = LogFactory.getLog(BidirectionalManyToManyAnnotator.class); /** Process the features of the eclass */ public void annotate(PAnnotatedEReference aReference) { final String featureLogStr = aReference.getModelEReference().getName() + "/" + aReference.getModelEReference().getEContainingClass().getName(); if (aReference.getOneToMany() != null || aReference.getOneToOne() != null || aReference.getManyToOne() != null) { throw new StoreMappingException("The feature/eclass " + featureLogStr + " should be a ManyToMany but " + "it already has a OneToMany, OneToOne or ManyToOne annotation"); } final EReference eReference = (EReference) aReference.getModelElement(); final EReference eOpposite = eReference.getEOpposite(); assert (eOpposite != null && eOpposite.isMany()); ManyToMany mtm = aReference.getManyToMany(); final boolean mtmWasSet = mtm != null; // mtm was set manually if (mtm == null) { log.debug("Adding manytomany annotations to ereference: " + featureLogStr); mtm = getFactory().createManyToMany(); aReference.setManyToMany(mtm); mtm.setEModelElement(eReference); } else { log.debug("ManyToMany present check if default information should be added"); } if (eReference.isContainment() || getPersistenceOptions().isSetDefaultCascadeOnNonContainment()) { setCascade(mtm.getCascade(), eReference.isContainment()); } if (mtm.getTargetEntity() == null) { mtm.setTargetEntity(getEntityName(eReference.getEReferenceType())); } if (getPersistenceOptions().isSetForeignKeyNames() && aReference.getForeignKey() == null) { aReference.setForeignKey(createFK(aReference)); } // determine where to place the jointable annotation and where to place // the mappedby // use a certain logic to determine as each is only set on one side // note that the join is always set on the other side of mapped by! // note that we can not do setJoinHere = !setMappedByHere because there // are situations // that even for mtm no mappedby is set on either side, nl. in case of // containment // also check if the other side has a (manual) manytomany with mappedby // set // bugzilla: 164808 final PAnnotatedEReference otherPA = aReference.getPaModel().getPAnnotated(eOpposite); if (mtm.getMappedBy() == null && setMappedBy(eReference) && (otherPA.getManyToMany() == null || otherPA.getManyToMany().getMappedBy() == null)) { mtm.setMappedBy(eOpposite.getName()); } JoinTable joinTable = aReference.getJoinTable(); if (joinTable == null) { joinTable = getFactory().createJoinTable(); aReference.setJoinTable(joinTable); } joinTable.setEModelElement(eReference); // set unique and indexed // disabled because indexed = false now for mtm, // to overcome this the user has to explicitly set a mtm annotation. if (!mtmWasSet) { log.debug("Setting indexed and unique from ereference.isOrdered/isUnique " + "because mtm was not set manually!"); mtm.setIndexed(!getPersistenceOptions().alwaysMapListAsBag() && eReference.isOrdered()); } // NOTE that the ejb3 spec states that the jointable should be the // concatenation of the // tablenames of the owning entities with an underscore, this will // quickly lead to nameclashes // in the case there is more than one relation between two classes. This // can be pretty likely // if the inheritance strategy is single_table. // now possibility to use a different naming strategy if (joinTable.getName() == null) { joinTable.setName(getSqlNameStrategy().getJoinTableName(aReference)); } if (joinTable.getJoinColumns().size() == 0) { final List<String> names = getSqlNameStrategy().getJoinTableJoinColumns(aReference, false); joinTable.getJoinColumns().addAll(getJoinColumns(names, false, true, mtm)); } if (joinTable.getInverseJoinColumns().size() == 0) { final List<String> names = getSqlNameStrategy().getJoinTableJoinColumns(aReference, true); joinTable.getInverseJoinColumns().addAll(getJoinColumns(names, false, true, mtm)); } } }