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.order;
009
010import java.util.ArrayList;
011import java.util.HashSet;
012import java.util.List;
013import java.util.Set;
014
015import javax.jmi.model.GeneralizableElement;
016import javax.jmi.reflect.RefBaseObject;
017
018import net.mdatools.modelant.core.api.Order;
019
020/**
021 * State a list of metamodel classes to order their instances.
022 * The instances of different (listed) classes are ordered according to the positions of those classes in the list.
023 * Instances of not listed classes are just kept as they are, after any instances of listed classes.
024 * @author Rusi Popov (popovr@mdatools.net)
025 */
026public class OrderByClass implements Order {
027
028  /**
029   * List of class names defining their order
030   */
031  private final List<String> classNames = new ArrayList<String>();
032  private final Set<String> knownNotCoveredClasses = new HashSet<String>();
033  
034  public int compare(RefBaseObject o1, RefBaseObject o2) {
035    int index1;
036    int index2;
037
038    index1 = getIndexOf((GeneralizableElement) o1.refMetaObject());
039    index2 = getIndexOf((GeneralizableElement) o2.refMetaObject());
040    
041    return index1-index2;
042  }
043
044  /**
045   * post-condition:
046   *   knownNotCoveredClasses is updated with classes known not pertaining to the list
047   * @param target not null MOF Element representing a superclass of a model element to order
048   * @return the minimal index of the model class of the target or of its superclasses in classNames list. If 
049   *         no (super)class found among classNames, MAX_INT is returned  
050   */
051  private int getIndexOf(GeneralizableElement target) {
052    int result;
053    String metaClassName;
054    
055    metaClassName = target.getName();
056    
057    result = classNames.indexOf( metaClassName );
058    if ( result < 0 ) { // not listed explicitly, search superclasses
059      result = Integer.MAX_VALUE;
060      
061      if ( !knownNotCoveredClasses.contains( metaClassName ) ) { // still decision on the class is not made        
062        for (GeneralizableElement superClass : (List<GeneralizableElement>) target.getSupertypes()) {
063          result = Math.min( result, getIndexOf( superClass ) );        
064        }
065        if ( result == Integer.MAX_VALUE ) { // the class is not covered
066          knownNotCoveredClasses.add( metaClassName );
067        }
068      }
069    }
070    return result;
071  }
072  
073  /**
074   * Add a single class name to the list of classes. The order of a model element's class name within the list 
075   * compared the order other elements' class name defines the order of those elements.
076   * with the order of other
077   */
078  public ClassName createClass() {
079    return new ClassName();
080  }
081  
082  /**
083   * State the text contents of &lt;class&gt; element as a single class name to order against.
084   */
085  public class ClassName {
086    public void addText(String className) {
087      classNames.add( className );
088    }
089  }
090}