001/* 002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved. 003 * 004 * This program and the accompanying materials are made available under the terms of the 005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at 006 * http://www.eclipse.org/legal/epl-v20.html 007 */ 008package net.mdatools.modelant.core.name; 009 010import java.util.Map; 011import java.util.logging.Level; 012import java.util.logging.Logger; 013 014import javax.jmi.model.Association; 015import javax.jmi.reflect.JmiException; 016import javax.jmi.reflect.RefAssociation; 017import javax.jmi.reflect.RefAssociationLink; 018import javax.jmi.reflect.RefObject; 019import javax.jmi.reflect.RefPackage; 020 021import net.mdatools.modelant.core.api.Procedure; 022import net.mdatools.modelant.core.api.model.ConstructProcedure; 023import net.mdatools.modelant.core.api.model.NameMapping; 024import net.mdatools.modelant.core.api.name.AssociationName; 025import net.mdatools.modelant.core.api.name.Name; 026import net.mdatools.modelant.core.api.name.PackageName; 027 028/** 029 * A mechanism to locate a RefAssociation by its qualified name in the metamodel 030 * @author Rusi Popov (popovr@mdatools.net) 031 */ 032public class AssociationNameImpl extends NameImpl<PackageName> implements AssociationName { 033 034 private static final Logger LOGGER = Logger.getLogger( AssociationNameImpl.class.getName() ); 035 036 public AssociationNameImpl(String packageName) { 037 super(packageName); 038 } 039 040 public AssociationNameImpl(PackageName parent, String name) { 041 super(parent, name); 042 } 043 044 public AssociationNameImpl(Association association) { 045 super(new PackageNameImpl(association.getContainer()), association.getName()); 046 } 047 048 /** 049 * @param qualifiedName not null 050 * @return the Association Name that represents the qualified name provided, 051 * @throws IllegalArgumentException when qualifiedName is empty 052 */ 053 public static AssociationName parseQualifiedClassName(String qualifiedName) throws IllegalArgumentException { 054 AssociationName result; 055 PackageName pack; 056 String[] names; 057 058 pack = null; 059 names = qualifiedName.split( METAMODEL_PATH_SEPARATOR_PARSE ); 060 for (int i=0; i<names.length-1; i++) { 061 pack = new PackageNameImpl( pack, names[i] ); 062 } 063 if (names.length > 0) { 064 result = new AssociationNameImpl(pack, names[names.length-1]); 065 } else { 066 result = null; 067 } 068 return result; 069 } 070 071 /** 072 * @param rootPackage not null extent 073 */ 074 public RefAssociation getMetaAssociation(RefPackage rootPackage) throws JmiException { 075 RefAssociation result; 076 RefPackage ownerPackage; 077 078 assert rootPackage != null : "Expected a non-null package"; 079 080 if ( getOwner() == null ) { 081 ownerPackage = rootPackage; 082 } else { 083 ownerPackage = getOwner().getMetaPackage( rootPackage ); 084 } 085 086 try { 087 result = ownerPackage.refAssociation( getName() ); 088 } catch (JmiException ex) { 089 throw new IllegalArgumentException("Looking up the association "+ this 090 + " reached " + PRINT_MODEL_ELEMENT.execute( ownerPackage ) 091 + " for which retrieving the nested class '"+getName()+"'" 092 + " caused ",ex); 093 } 094 return result; 095 } 096 097 /** 098 * @see Name#constructName(Name, String) 099 */ 100 public Name<PackageName> constructName(PackageName parent, String name) { 101 return new AssociationNameImpl(parent, name); 102 } 103 104 /** 105 * @return non-null transformation of source model Links into target model links 106 * @see net.mdatools.modelant.core.api.name.Name#constructTransfromation() 107 */ 108 public ConstructProcedure<RefAssociationLink> constructTransfromation() { 109 return newForwardLinkProduction(); 110 } 111 112 /** 113 * This represents a target model association 114 * @return non-null producer of transformations of source model links to target model links in the same direction, e.g. the source of the produced 115 * link is the object that corresponds to the source of the original link, the same is for link targets 116 */ 117 public ConstructProcedure<RefAssociationLink> newForwardLinkProduction() { 118 return new ConstructProcedure<RefAssociationLink>() { 119 120 public Procedure<RefAssociationLink> construct(RefPackage sourceExtent, 121 RefPackage targetExtent, Map<RefObject, RefObject> objectsMap, NameMapping valueMapping) throws RuntimeException, IllegalArgumentException { 122 Procedure<RefAssociationLink> result; 123 RefAssociation associationClass; 124 Association association; 125 126 associationClass = AssociationNameImpl.this.getMetaAssociation(targetExtent); 127 association = (Association) associationClass.refMetaObject(); 128 129 if ( association.isDerived() ) { // the derived target associations are NOT copied 130 result = Procedure.EMPTY; 131 132 } else { 133 result = new Procedure<RefAssociationLink>() { 134 public void execute(RefAssociationLink link) throws RuntimeException, IllegalArgumentException { 135 RefObject target; 136 RefObject source; 137 138 source = objectsMap.get(link.refFirstEnd()); 139 target = objectsMap.get(link.refSecondEnd()); 140 141 if ( source != null ) { 142 if ( target != null ) { 143 associationClass.refAddLink(source, target); 144 } else { 145 LOGGER.log( Level.INFO, "{0} mapped to null", PRINT_MODEL_ELEMENT.execute( link.refSecondEnd() )); 146 } 147 } else { 148 LOGGER.log( Level.INFO, "{0} mapped to null", PRINT_MODEL_ELEMENT.execute( link.refFirstEnd() )); 149 } 150 } 151 }; 152 } 153 return result; 154 } 155 }; 156 } 157 158 /** 159 * This represents a target model association 160 * @return non-null producer of transformations of source model links to target model links in the opposite direction, e.g. the source of the produced 161 * link is the object that corresponds to the target of the original link, the same is for link targets 162 */ 163 public ConstructProcedure<RefAssociationLink> newBackwardLinkProduction() { 164 return new ConstructProcedure<RefAssociationLink>() { 165 166 public Procedure<RefAssociationLink> construct(RefPackage sourceExtent, 167 RefPackage targetExtent, Map<RefObject, RefObject> objectsMap, NameMapping valueMapping) throws RuntimeException, IllegalArgumentException { 168 Procedure<RefAssociationLink> result; 169 RefAssociation associationClass; 170 Association association; 171 172 associationClass = AssociationNameImpl.this.getMetaAssociation(targetExtent); 173 association = (Association) associationClass.refMetaObject(); 174 175 if ( association.isDerived() ) { // the derived target associations are NOT copied 176 result = Procedure.EMPTY; 177 178 } else { 179 result = new Procedure<RefAssociationLink>() { 180 public void execute(RefAssociationLink link) throws RuntimeException, IllegalArgumentException { 181 RefObject target; 182 RefObject source; 183 184 source = objectsMap.get(link.refFirstEnd()); 185 target = objectsMap.get(link.refSecondEnd()); 186 187 if ( source != null ) { 188 if ( target != null ) { 189 associationClass.refAddLink(target, source); 190 } else { 191 LOGGER.log( Level.INFO, "{0} mapped to null", PRINT_MODEL_ELEMENT.execute( link.refSecondEnd() )); 192 } 193 } else { 194 LOGGER.log( Level.INFO, "{0} mapped to null", PRINT_MODEL_ELEMENT.execute( link.refFirstEnd() )); 195 } 196 } 197 }; 198 } 199 return result; 200 } 201 }; 202 } 203}