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; 011 012import javax.jmi.model.Association; 013import javax.jmi.model.Classifier; 014import javax.jmi.model.Feature; 015import javax.jmi.model.ModelElement; 016import javax.jmi.model.MofPackage; 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.ClassName; 025import net.mdatools.modelant.core.api.name.Name; 026import net.mdatools.modelant.core.operation.element.PrintModelElement; 027import net.mdatools.modelant.core.util.key.Hash; 028 029/** 030 * A key in package/type/value mapping 031 * @param <P> the type of the parent/owner name 032 * @author Rusi Popov (popovr@mdatools.net) 033 */ 034public class NameImpl<P extends Name<?>> implements Name<P> { 035 036 /** 037 * A common constant of "no name" and "stop mapping", as null is not name acceptable value 038 */ 039 public static final Name<?> NO_MAP_NAME = new NameImpl<>("$NO_MAP_NAME$"); 040 041 protected static final PrintModelElement PRINT_MODEL_ELEMENT = new PrintModelElement(); 042 043 private final P owner; 044 private final String name; 045 private final int hash; 046 047 /** 048 * Construct root name 049 * @param name not null, not empty 050 */ 051 protected NameImpl(String name) { 052 this(name, null); 053 } 054 055 /** 056 * Construct a name in the context of the owner name 057 * @param owner may be null, when null provided this is equal to new Name(name) 058 * @param name not null, not empty 059 */ 060 protected NameImpl(P owner, String name) { 061 this(name, owner); 062 } 063 064 /** 065 * Construct a name in the context of the owner name 066 * @param owner not null 067 * @param name not null, not empty 068 */ 069 private NameImpl(String name, P owner) { 070 int hash; 071 072 assert name != null : "Expected non-null name"; 073 074 this.name = name; 075 this.owner = owner; 076 077 hash = getClass().hashCode(); 078 if ( owner != null ) { 079 hash = (hash << 2) + owner.hashCode(); 080 } 081 hash = (hash << 2) + Hash.hash( name ); 082 this.hash = hash; 083 } 084 085 /** 086 * @param modelElement non-null model element 087 * @return the qualified name of the meta object (MOF element (class) of the metamodel), that describes 088 * the provided model element 089 */ 090 public static ClassName constructQualifiedMetaObjectName(RefObject modelElement) { 091 return (ClassName) constructQualifiedElementName( (ModelElement) modelElement.refMetaObject() ); 092 } 093 094 095 /** 096 * @param metaObject non-null MOF object 097 * @return the qualified name of the MOF element, calculated down the containment relation 098 */ 099 public static Name constructQualifiedElementName(ModelElement metaObject) { 100 Name result; 101 102 if ( metaObject instanceof MofPackage ) { 103 result = new PackageNameImpl( (PackageNameImpl) constructQualifiedElementName( metaObject.getContainer() ), 104 metaObject.getName()); 105 } else if ( metaObject instanceof Feature ) { 106 result = new FieldNameImpl( (ClassNameImpl) constructQualifiedElementName( metaObject.getContainer() ), 107 metaObject.getName()); 108 } else if ( metaObject instanceof Association ) { 109 result = new AssociationNameImpl( (PackageNameImpl) constructQualifiedElementName( metaObject.getContainer() ), 110 metaObject.getName()); 111 } else if ( metaObject instanceof Classifier ) { 112 result = new ClassNameImpl( (PackageNameImpl) constructQualifiedElementName( metaObject.getContainer() ), 113 metaObject.getName()); 114 } else { 115 result = null; 116 } 117 return result; 118 } 119 120 121 public final boolean isEmpty() { 122 boolean result; 123 result = name.isEmpty(); 124 return result; 125 } 126 127 /** 128 * @see java.lang.Object#hashCode() 129 */ 130 public final int hashCode() { 131 return hash; 132 } 133 134 /** 135 * @see java.lang.Object#equals(java.lang.Object) 136 */ 137 public final boolean equals(Object obj) { 138 boolean result; 139 NameImpl other; 140 141 result = obj == this; 142 143 if ( !result && obj != null && obj.getClass() == getClass() ) { 144 other = (NameImpl) obj; 145 146 result = (owner == null && other.owner == null 147 || owner != null && owner.equals( other.owner )) 148 && name.equals( other.name ); 149 } 150 return result; 151 } 152 153 /** 154 * @return the qualified name this represents 155 */ 156 public String toString() { 157 String result; 158 159 if ( owner == null ) { 160 result = name; 161 } else { 162 result = owner.toString()+METAMODEL_PATH_SEPARATOR+name; 163 } 164 return result; 165 } 166 167 /** 168 * @return 169 * @see net.mdatools.modelant.core.api.name.Name#getOwner() 170 */ 171 public final P getOwner() { 172 return owner; 173 } 174 175 /** 176 * @return 177 * @see net.mdatools.modelant.core.api.name.Name#getName() 178 */ 179 public final String getName() { 180 return name; 181 } 182 183 /** 184 * @param qualifiedName not null 185 * @return the Name that represents the qualified name provided, 186 */ 187 public static Name parseQualifiedName(String qualifiedName) { 188 NameImpl result; 189 String[] names; 190 191 result = null; 192 names = qualifiedName.split( METAMODEL_PATH_SEPARATOR_PARSE ); 193 for (String name:names) { 194 result = new NameImpl( result, name ); 195 } 196 return result; 197 } 198 199 /** 200 * @see net.mdatools.modelant.core.api.name.Name#constructName(net.mdatools.modelant.core.api.name.Name, java.lang.String) 201 */ 202 public Name<P> constructName(P parent, String name) { 203 return new NameImpl<P>(parent, name); 204 } 205 206 /** 207 * @see net.mdatools.modelant.core.api.name.Name#constructNoTransfromation() 208 */ 209 public final ConstructProcedure<RefAssociationLink> constructNoTransfromation() { 210 return new ConstructProcedure<RefAssociationLink>() { 211 public Procedure<RefAssociationLink> construct(RefPackage sourceExtent, RefPackage targetExtent, Map<RefObject, RefObject> objectsMap, NameMapping valueMapping) { 212 return Procedure.EMPTY; 213 } 214 }; 215 } 216 217 /** 218 * Override in subclasses 219 * @see net.mdatools.modelant.core.api.name.Name#constructTransfromation() 220 */ 221 public ConstructProcedure<?> constructTransfromation() { 222 return new ConstructProcedure<RefAssociationLink>() { 223 public Procedure<RefAssociationLink> construct(RefPackage sourceExtent, RefPackage targetExtent, Map<RefObject, RefObject> objectsMap, NameMapping valueMapping) { 224 return Procedure.EMPTY; 225 } 226 }; 227 } 228}