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.selector;
009
010import java.util.ArrayList;
011import java.util.Collection;
012
013import javax.jmi.model.ModelElement;
014import javax.jmi.reflect.JmiException;
015import javax.jmi.reflect.RefObject;
016import javax.jmi.reflect.RefPackage;
017
018import net.mdatools.modelant.core.api.Selector;
019import net.mdatools.modelant.core.api.name.Name;
020import net.mdatools.modelant.core.util.Navigator;
021
022/**
023 * Selector of a metamodel class with the provided qualified name
024 * @author popovr
025 */
026public class SelectByQualifiedName implements Selector<RefPackage, RefObject> {
027
028  /**
029   * The qualified name of the object(s) to retrieve
030   * not null
031   */
032  private final String qualifiedName;
033
034  /**
035   * @param qualifiedName not null, not empty name of a MOF Class instance in the metamodel
036   */
037  public SelectByQualifiedName(String qualifiedName) {
038    if ( qualifiedName == null || qualifiedName.trim().isEmpty() ) { // iteration on model class instances
039      throw new IllegalArgumentException( "Empty qualified name provided ");
040    }
041    this.qualifiedName = qualifiedName;
042  }
043
044  /**
045   * @param sourceExtent not null extent where to collect objects in
046   * @return non-null list of one element - the metaobject, describing the metaclass
047   */
048  public Collection<RefObject> execute(RefPackage sourceExtent) throws JmiException {
049    Collection<RefObject> result;
050    Collection<RefObject> allObjects;
051    String[] parsedQualifiedName;
052
053    parsedQualifiedName = Name.parseQualifiedName( qualifiedName );
054
055    result = new ArrayList<>();
056
057    allObjects = Navigator.getAllObjects( sourceExtent );
058    for (RefObject object : allObjects) {
059      if ( matches((ModelElement) object, parsedQualifiedName, parsedQualifiedName.length-1) ) {
060        result.add(object);
061      }
062    }
063
064    assert !result.isEmpty()
065           : "Expected a non-empty selection found for qualified name: "+qualifiedName;
066    return result;
067  }
068
069  /**
070   * @param object not null
071   * @param parsedQualifiedName not null parsed qualified name
072   * @param i < parsedQualifiedName.length
073   * @return true if object's name = parsedQualifiedName[i] and object's namespace matches the
074   *         parsed name [i-1]
075   */
076  private boolean matches(ModelElement object, String[] parsedQualifiedName, int i) {
077    boolean result;
078
079    if ( i < 0 ) {
080      result = true;
081
082    } else if ( object == null ) { // nothing to match
083      result = false;
084
085    } else {
086      result = parsedQualifiedName[i].equals( object.getName() )
087               && ( i == 0
088                    && object.getContainer() == null // matched the root package
089                    || i > 0
090                       && matches( object.getContainer(), parsedQualifiedName, i-1 ));
091    }
092    return result;
093  }
094}