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.operation.model.transform; 009 010import java.util.Collection; 011import java.util.Map; 012import java.util.logging.Level; 013import java.util.logging.Logger; 014 015import javax.jmi.reflect.RefEnum; 016import javax.jmi.reflect.RefObject; 017import javax.jmi.reflect.RefPackage; 018import javax.jmi.reflect.RefStruct; 019 020import net.mdatools.modelant.core.api.Operation; 021import net.mdatools.modelant.core.api.Procedure; 022import net.mdatools.modelant.core.api.model.NameMapping; 023import net.mdatools.modelant.core.api.name.EnumValueName; 024import net.mdatools.modelant.core.api.name.StructName; 025import net.mdatools.modelant.core.name.EnumValueNameImpl; 026import net.mdatools.modelant.core.name.StructNameImpl; 027import net.mdatools.modelant.core.operation.element.PrintModelElement; 028 029/** 030 * Copy a single attribute operation from the source attribute in the source object 031 * to the target attribute in the target object. 032 */ 033public class CopyAttributeImpl implements Procedure<RefObject> { 034 035 private static final Logger LOGGER = Logger.getLogger( CopyAttributeImpl.class.getName() ); 036 037 private static final PrintModelElement PRINT_MODEL_ELEMENT = new PrintModelElement(); 038 039 private final String sourceName; 040 private final String targetName; 041 private final Map<RefObject, RefObject> objectsMap; 042 private final RefPackage sourceExtent; 043 private final RefPackage targetExtent; 044 private final NameMapping valueMapping; 045 046 /** 047 * @param sourceName not null source attribute name 048 * @param targetName not null target attribute name 049 * @param objectsMap not null mapping of source model elements to target model elements 050 * @param targetExtent not null target model extent 051 * @param valueMapping not null 052 */ 053 public CopyAttributeImpl(String sourceName, 054 String targetName, 055 Map<RefObject, RefObject> objectsMap, 056 RefPackage sourceExtent, 057 RefPackage targetExtent, 058 NameMapping valueMapping) { 059 this.sourceName = sourceName; 060 this.targetName = targetName; 061 this.objectsMap = objectsMap; 062 this.sourceExtent = sourceExtent; 063 this.targetExtent = targetExtent; 064 this.valueMapping = valueMapping; 065 } 066 067 /** 068 * Copy the value of the source filed as a value of the target field with some 069 * type transformation. 070 * 071 * Copied are single value attributes, assuming that the multiple-valued attributes 072 * are associations. 073 * 074 * @param source not null source object 075 */ 076 public void execute(RefObject source) throws IllegalArgumentException { 077 Object sourceValue; 078 RefObject target; 079 080 target = objectsMap.get( source ); 081 if ( target != null ) { 082 try { 083 sourceValue = source.refGetValue( sourceName ); 084 085 } catch (Exception ex) { 086 throw new IllegalArgumentException( "Getting '"+sourceName+"' attribute of object " 087 +PRINT_MODEL_ELEMENT.execute( source ) 088 + " instance of " 089 +PRINT_MODEL_ELEMENT.execute( source.refMetaObject() )+" failed with: ", ex ); 090 } 091 092 if ( sourceValue instanceof RefStruct ) { 093 assignStructValue((RefStruct) sourceValue, target); 094 095 } else if ( sourceValue instanceof RefEnum ) { 096 assignEnumValue((RefEnum) sourceValue, target); 097 098 } else if ( sourceValue instanceof RefObject ) { // this object should have been mapped 099 assignObjectVlaue((RefObject) sourceValue, target ); 100 101 } else if (sourceValue != null) { // any other non-JMI/non-MOF object 102 setValue(sourceValue, target); 103 } 104 } 105 } 106 107 /** 108 * Convert and assign a struct value to the target model element. 109 * @param sourceStruct not null source struct value 110 * @param target not null target model value to update 111 */ 112 private void assignStructValue(RefStruct sourceStruct, RefObject target) { 113 RefStruct targetStruct; 114 Operation<RefStruct> operation; 115 116 operation = valueMapping.mapStruct(new StructNameImpl(sourceExtent, sourceStruct), 117 targetExtent, 118 objectsMap); 119 try { 120 targetStruct = operation.execute( sourceStruct ); 121 setValue(targetStruct, target); 122 } catch (Exception ex) { 123 LOGGER.log( Level.INFO, 124 "Mapping source struct " 125 +PRINT_MODEL_ELEMENT.execute( sourceStruct ) 126 +" caused:", ex); 127 } 128 } 129 130 /** 131 * Convert and assign an enum value to the target model element. 132 * @param sourceValue not null enum value 133 * @param target not null target model value to update 134 */ 135 private void assignEnumValue(RefEnum sourceValue, RefObject target) { 136 EnumValueName targetEnumName; 137 138 targetEnumName = valueMapping.mapEnum( new EnumValueNameImpl(sourceExtent, sourceValue)); 139 140 if ( targetEnumName != null ) { 141 setValue( targetEnumName.lookupValue( targetExtent ), target ); 142 143 } else { 144 LOGGER.log( Level.INFO, 145 "The source enum value of " 146 + PRINT_MODEL_ELEMENT.execute( sourceValue ) 147 + " is not mapped. Skipped "); 148 } 149 } 150 151 /** 152 * @param sourceValue not null object value to convert and assign to the targetField of the target object 153 * @param target not null target model object to update 154 */ 155 private void assignObjectVlaue(RefObject sourceValue, RefObject target) { 156 Object convertedValue; 157 158 convertedValue = objectsMap.get( sourceValue ); 159 setValue(convertedValue, target); 160 161 LOGGER.log( Level.FINE, "{0} mapped to {1}", 162 new Object[] {PRINT_MODEL_ELEMENT.toPrint( sourceValue ), 163 PRINT_MODEL_ELEMENT.toPrint( convertedValue )}); 164 } 165 166 /** 167 * @param convertedValue not null 168 * @param target not null 169 */ 170 private void setValue(Object convertedValue, RefObject target) { 171 Object targetValue; 172 173 try { 174 targetValue = target.refGetValue(targetName); 175 176 if ( targetValue instanceof Collection ) { 177 if ( convertedValue instanceof Collection ) { 178 ((Collection) targetValue).addAll((Collection) convertedValue); 179 } else { 180 ((Collection) targetValue).add( convertedValue ); 181 } 182 } else { 183 target.refSetValue( targetName, convertedValue ); 184 } 185 } catch (Exception ex) { 186 throw new IllegalArgumentException( "Setting '"+targetName+"' to value: '" 187 +PRINT_MODEL_ELEMENT.execute( convertedValue ) 188 +"' on target object " 189 +PRINT_MODEL_ELEMENT.execute( target ) 190 + " instance of " 191 +PRINT_MODEL_ELEMENT.execute( target.refMetaObject() )+" failed with: ", ex); 192 } 193 } 194 195 /** 196 * @see java.lang.Object#toString() 197 */ 198 public String toString() { 199 return "Copy from "+sourceName+" to "+targetName; 200 } 201}