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.List;
011
012import javax.jmi.reflect.InvalidNameException;
013import javax.jmi.reflect.JmiException;
014import javax.jmi.reflect.RefBaseObject;
015import javax.jmi.reflect.RefClass;
016import javax.jmi.reflect.RefEnum;
017import javax.jmi.reflect.RefPackage;
018
019import net.mdatools.modelant.core.api.name.EnumValueName;
020import net.mdatools.modelant.core.api.name.Name;
021import net.mdatools.modelant.core.api.name.PackageName;
022
023/**
024 * A key in package/type/value mapping
025 * @author Rusi Popov (popovr@mdatools.net)
026 */
027public class EnumValueNameImpl extends NameImpl<Name<?>> implements EnumValueName {
028
029  public EnumValueNameImpl(String name) {
030    super(name);
031  }
032
033  public EnumValueNameImpl(Name<?> parentName, String name) {
034    super(parentName, name);
035  }
036
037  public EnumValueNameImpl(RefPackage targetExtent, RefEnum enumValue) {
038    this(constructEnumClassName(enumValue.refTypeName(), targetExtent), enumValue.toString());
039  }
040
041  /**
042   * @param qualifiedName not null, not empty qualified name of the Enum Class
043   * @param targetExtent not null
044   * @return the class name of that Enum
045   */
046  private static Name<?> constructEnumClassName(List<String> qualifiedName, RefPackage targetExtent) {
047    Name<?> result;
048    String name;
049    Name packageName;
050    RefBaseObject namespace;
051
052    namespace = targetExtent;
053    packageName = null;
054    for (int i=0; i<qualifiedName.size()-1; i++) {
055      name = qualifiedName.get( i );
056
057      if ( namespace instanceof RefPackage ) { // the current name is a name of a package or class, packageName is a name of a package so far
058        try {
059          namespace = ((RefPackage) namespace).refPackage( name );
060          packageName = new PackageNameImpl((PackageName) packageName, name);
061
062        } catch (InvalidNameException ex) { // name is not a package, it could be only a class
063          namespace = ((RefPackage) namespace).refClass( name );
064          packageName = new ClassNameImpl((PackageName) packageName, name);
065        }
066      } else { // namespace is a Class owning at most an enumeration
067        throw new IllegalArgumentException("Resolving "+qualifiedName
068                                           +" enumeration name, reached "+PRINT_MODEL_ELEMENT.execute( namespace )
069                                           +" which cannot contain nested "+name);
070      }
071    }
072    if ( qualifiedName.size() > 0 ) {
073      result = new ClassNameImpl(packageName, qualifiedName.get( qualifiedName.size()-1 ));
074    } else {
075      result = null;
076    }
077    return result;
078  }
079
080  /**
081   * @see net.mdatools.modelant.core.api.name.Name#constructName(net.mdatools.modelant.core.api.name.Name, java.lang.String)
082   */
083  public Name<Name<?>> constructName(Name<?> parent, String name) {
084    return new EnumValueNameImpl(parent, name);
085  }
086
087  /**
088   * @see net.mdatools.modelant.core.api.name.EnumValueName#lookupValue(javax.jmi.reflect.RefPackage)
089   */
090  public RefEnum lookupValue(RefPackage targetExtent) throws JmiException {
091    RefEnum result;
092    Name enumClassName;
093    Name enumClassNamespace;
094    PackageName enumClassNamespaceNamespace;
095    RefPackage enumClassNamespacePackage;
096    RefPackage enumClassPackage;
097    RefClass enumClassClass;
098
099    if ( getOwner() == null
100         || getOwner().getOwner() == null) {
101      throw new InvalidNameException( toString(), "Expected a parent class and package name provided");
102    }
103
104    enumClassName = getOwner();
105    enumClassNamespace = enumClassName.getOwner();
106    enumClassNamespaceNamespace = (PackageName) enumClassNamespace.getOwner();
107
108    if ( enumClassNamespaceNamespace != null ) {
109      enumClassNamespacePackage = enumClassNamespaceNamespace.getMetaPackage( targetExtent );
110    } else {
111      enumClassNamespacePackage = targetExtent;
112    }
113
114    // in enumClassNamespaceNamespace, enumClassNamespace could be a class or package
115    // try both options, which one will work
116    try {
117      enumClassPackage = enumClassNamespacePackage.refPackage( enumClassNamespace.getName() );
118      result = enumClassPackage.refGetEnum( enumClassName.getName(), getName() );
119
120    } catch (InvalidNameException ex) {
121      enumClassClass = enumClassNamespacePackage.refClass( enumClassNamespace.getName() );
122      result = enumClassClass.refGetEnum( enumClassName.getName(), getName() );
123    }
124    return result;
125  }
126}