/** * Optimus, framework for Model Transformation * * Copyright (C) 2013 Worldline or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package net.atos.optimus.m2t.merger.java.core; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.atos.optimus.common.tools.jdt.JavaCodeHelper; import net.atos.optimus.m2t.merger.java.core.internal.MergerLogger; import net.atos.optimus.m2t.merger.java.core.internal.MergerLoggerMessages; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; /** * @author Maxence Vanbésien (mvaawl@gmail.com) * @since 1.0 */ public class DefaultMergingStrategy implements MergingStrategy { private ASTRewrite astr = null; public DefaultMergingStrategy() { } public final ASTRewrite getASTRewrite() { return this.astr; } public final void setASTRewrite(ASTRewrite astr) { this.astr = astr; } public void mergeStrategy(Annotation existingAnnotation, Annotation generatedAnnotation, ListRewrite lw) { if (existingAnnotation == null && generatedAnnotation == null) { return; } if (existingAnnotation == null) { if (MergerLogger.enabled()) MergerLogger.log(MergerLoggerMessages.BODYDECL_ANNOADDED.value(generatedAnnotation.toString(), JavaCodeHelper.getName(generatedAnnotation.getParent()), JavaCodeHelper.getDescription(generatedAnnotation.getParent()))); /* * This annotation is present in the generated code AND This * annotation is not present in the existing code => Add this * annotation in the merge result */ lw.insertFirst(generatedAnnotation, null); } else { if (generatedAnnotation == null) { /* * This annotation is present into the existing fragment AND * This annotation is not present into the generated fragment * AND This annotation is a predefined one => This annotation * must be removed - Use cases : Change association multiplicity * (from OneToOne to OneToMany),... */ if (MergerLogger.enabled()) MergerLogger.log(MergerLoggerMessages.BODYDECL_ANNOREMOVED.value(existingAnnotation.toString(), JavaCodeHelper.getName(existingAnnotation.getParent()), JavaCodeHelper.getDescription(existingAnnotation.getParent()))); lw.remove(existingAnnotation, null); } else { /* * This annotation is present into the existing fragment AND * This annotation is present into the generated fragment => * Annotation attributes must be merged */ this.mergeAnnotationAttributes(existingAnnotation, generatedAnnotation, lw); } } } /** * Annotation attributes handlings for annotation's type located in the * generated annotation property file. * * @param annotationInTheExistingFragment * @param existingAnnotation * @param lw * @param generatedAnnotations * @param annoName */ private void mergeAnnotationAttributes(Annotation annotationInTheExistingFragment, Annotation annotationInTheGeneratedFragment, ListRewrite lw) { if (annotationInTheExistingFragment.isMarkerAnnotation()) { /* * The annotation used inside the existing fragment is a marker * annotation (annotation without attribute) */ if (!annotationInTheGeneratedFragment.isMarkerAnnotation()) { /* * The annotation used inside the generated fragment contains * one or many attributes. The annotation used inside the * generated fragment must be used in the result */ lw.replace(annotationInTheExistingFragment, annotationInTheGeneratedFragment, null); } } else { if (annotationInTheExistingFragment.isSingleMemberAnnotation()) { /* * The annotation used inside the existing fragment is a single * member annotation (annotation without only one attribute) */ if (annotationInTheGeneratedFragment.isSingleMemberAnnotation()) { /* * The annotation used inside the generated fragment * contains one value. Existing value must be replaced by * generated value. */ this.astr.replace(annotationInTheExistingFragment, annotationInTheGeneratedFragment, null); } else { if (annotationInTheGeneratedFragment.isNormalAnnotation()) { /* * The annotation used inside the generated fragment * contains several attributes. Existing value must be * replaced by generated value. */ lw.replace(annotationInTheExistingFragment, annotationInTheGeneratedFragment, null); } } } else { /* * The annotation used inside the existing fragment is a normal * annotation (annotation with several attributes) */ if (annotationInTheGeneratedFragment.isSingleMemberAnnotation()) { /* * What should be done in that case ? The existing * annotation has been probably enhance => Let the existing * content as before. */ } else { if (annotationInTheGeneratedFragment.isNormalAnnotation()) { /* * The annotation used inside the generated fragment * contains several attributes. Existing and generated * annotations must be merged. */ this.mergeAnnotationAttribute( (NormalAnnotation) annotationInTheExistingFragment, (NormalAnnotation) annotationInTheGeneratedFragment); } } } } } /** * Merge two annotations attribute */ @SuppressWarnings("unchecked") private void mergeAnnotationAttribute(NormalAnnotation annotationInTheExistingFragment, NormalAnnotation annotationInTheGeneratedFragment) { List<String> existingAnnotationAttributesToRemoved = new ArrayList<String>(1); List<MemberValuePair> existingAnnotationAttributes = annotationInTheExistingFragment .values(); List<MemberValuePair> generatedAnnotationAttributes = annotationInTheGeneratedFragment .values(); List<String> existingAnnotationAttributesNames = new ArrayList<String>(1); Map<String, MemberValuePair> generatedAnnotationAttributesMap = new HashMap<String, MemberValuePair>( 1); for (MemberValuePair mvp : existingAnnotationAttributes) { existingAnnotationAttributesNames.add(mvp.getName().getFullyQualifiedName()); } for (MemberValuePair mvp : generatedAnnotationAttributes) { generatedAnnotationAttributesMap.put(mvp.getName().getFullyQualifiedName(), mvp); } for (MemberValuePair mvp : existingAnnotationAttributes) { if (generatedAnnotationAttributesMap.containsKey(mvp.getName().getFullyQualifiedName())) { /* * The attribute is present in the existing fragment AND The * attribute is present in the generated fragment => The * attribute present in the existing fragment must be removed * and the attribute present in the generated fragment must be * copied in the result */ ListRewrite lw = this.astr.getListRewrite(annotationInTheExistingFragment, NormalAnnotation.VALUES_PROPERTY); lw.replace(mvp, generatedAnnotationAttributesMap.get(mvp.getName() .getFullyQualifiedName()), null); existingAnnotationAttributesToRemoved.add(mvp.getName().getFullyQualifiedName()); } } for (MemberValuePair mvp : generatedAnnotationAttributes) { if (!existingAnnotationAttributesNames.contains(mvp.getName().getFullyQualifiedName()) && !existingAnnotationAttributesToRemoved.contains(mvp.getName() .getFullyQualifiedName())) { /* * The attribute is not present in the existing fragment AND The * attribute is present in the generated fragment => The * attribute present in the generated fragment must be copied in * the result */ ListRewrite lw = this.astr.getListRewrite(annotationInTheExistingFragment, NormalAnnotation.VALUES_PROPERTY); lw.insertFirst(mvp, null); } else { // Nothing to do } } } }