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.topology; 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.RefObject; 017 018import net.mdatools.modelant.core.api.match.MatchingCriteria; 019 020/** 021 * This class represents criteria based on the target object's class, i.e. if the target object/model element 022 * is not of the class this criteria represents, then it just returns no associations. 023 * This is a composite criteria 024 * @author Rusi Popov (popovr@mdatools.net) 025 */ 026public class ClassCriteria implements MatchingCriteria { 027 028 private final MatchingCriteria nested; 029 private final Set<String> knownNotCovered = new HashSet<String>(11); 030 private final Set<String> knownSubclasses = new HashSet<String>(11); 031 032 /** 033 * @param className 034 * @param nested 035 */ 036 public ClassCriteria(String className, MatchingCriteria nested) { 037 this.nested = nested; 038 039 knownSubclasses.add( className ); 040 } 041 042 /** 043 * Returns the wrapped list of attributes only if the model element is of the metaclass with class name provided 044 * @see net.mdatools.modelant.core.operation.model.topology.SimpleCriteria#getAttributes(javax.jmi.reflect.RefObject) 045 */ 046 public List<String> getAttributes(RefObject forObject) { 047 List<String> result; 048 049 if ( isOfClass(forObject) ) { 050 result = nested.getAttributes( forObject ); 051 } else { 052 result = new ArrayList<String>(); 053 } 054 return result; 055 } 056 057 /** 058 * Returns the wrapped list of associations only if the model element is of the metaclass with class name provided 059 * @see net.mdatools.modelant.core.operation.model.topology.SimpleCriteria#getAssociations(RefObject) 060 */ 061 public List<String> getAssociations(RefObject forObject) { 062 List<String> result; 063 064 if ( isOfClass(forObject) ) { 065 result = nested.getAssociations( forObject ); 066 } else { 067 result = new ArrayList<String>(); 068 } 069 return result; 070 } 071 072 /** 073 * @param forObject 074 * @return true if forObject is of class with the simple name provided. 075 */ 076 private boolean isOfClass(RefObject forObject) { 077 boolean result; 078 List<GeneralizableElement> superclasses; 079 int i; 080 boolean decided; 081 GeneralizableElement superClass; 082 String forClassName; 083 String thisClassName; 084 085 superClass = (GeneralizableElement) forObject.refMetaObject(); 086 thisClassName = superClass.getName(); 087 088 // examine all superclasses 089 superclasses = new ArrayList<GeneralizableElement>(); 090 superclasses.add( superClass ); 091 092 i = 0; 093 do { 094 superClass = superclasses.get( i++ ); 095 096 forClassName = superClass.getName(); 097 098 result = knownSubclasses.contains( forClassName ); 099 decided = result 100 || knownNotCovered.contains( forClassName ); 101 if ( !decided ) { 102 superclasses.addAll( superClass.getSupertypes() ); 103 } 104 } while ( !decided && i < superclasses.size() ); 105 106 if ( result ) { 107 knownSubclasses.add( thisClassName ); 108 } else if ( !decided ) { // decision not found in the cache 109 knownNotCovered.add( thisClassName ); 110 } 111 return result; 112 } 113 114 /** 115 * @see java.lang.Object#toString() 116 */ 117 public String toString() { 118 StringBuilder builder; 119 120 builder = new StringBuilder(); 121 builder.append( "ClassCriteria [" ); 122 builder.append( "nested=" ).append( nested ).append( ", " ); 123 124 builder.append( "knownNotCovered=" ).append( knownNotCovered ).append( ", " ); 125 builder.append( "knownSubclasses=" ).append( knownSubclasses ); 126 builder.append( "]" ); 127 128 return builder.toString(); 129 } 130}