//------------------------------------------------------------------------------ // Copyright (c) 2005, 2006 IBM Corporation and others. // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // which accompanies this distribution, and is available at // http://www.eclipse.org/legal/epl-v10.html // // Contributors: // IBM Corporation - initial implementation //------------------------------------------------------------------------------ package org.eclipse.epf.library.configuration; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.epf.common.utils.ExtensionHelper; import org.eclipse.epf.common.utils.StrUtil; import org.eclipse.epf.library.ConfigHelperDelegate; import org.eclipse.epf.library.LibraryPlugin; import org.eclipse.epf.library.edit.PresentationContext; import org.eclipse.epf.library.edit.meta.TypeDefUtil; import org.eclipse.epf.library.edit.util.CategorySortHelper; import org.eclipse.epf.library.edit.util.MethodElementPropUtil; import org.eclipse.epf.library.edit.util.PracticePropUtil; import org.eclipse.epf.library.edit.util.PropUtil; import org.eclipse.epf.library.edit.util.SectionList; import org.eclipse.epf.library.edit.util.TngUtil; import org.eclipse.epf.library.util.LibraryUtil; import org.eclipse.epf.library.util.ResourceHelper; import org.eclipse.epf.uma.Activity; import org.eclipse.epf.uma.Artifact; import org.eclipse.epf.uma.CapabilityPattern; import org.eclipse.epf.uma.ContentDescription; import org.eclipse.epf.uma.ContentElement; import org.eclipse.epf.uma.CustomCategory; import org.eclipse.epf.uma.DeliveryProcess; import org.eclipse.epf.uma.DescribableElement; import org.eclipse.epf.uma.FulfillableElement; import org.eclipse.epf.uma.MethodConfiguration; import org.eclipse.epf.uma.MethodElement; import org.eclipse.epf.uma.MethodPackage; import org.eclipse.epf.uma.MethodPlugin; import org.eclipse.epf.uma.Practice; import org.eclipse.epf.uma.Role; import org.eclipse.epf.uma.RoleDescriptor; import org.eclipse.epf.uma.SupportingMaterial; import org.eclipse.epf.uma.Task; import org.eclipse.epf.uma.TaskDescriptor; import org.eclipse.epf.uma.UmaPackage; import org.eclipse.epf.uma.VariabilityElement; import org.eclipse.epf.uma.VariabilityType; import org.eclipse.epf.uma.WorkProduct; import org.eclipse.epf.uma.WorkProductDescriptor; import org.eclipse.epf.uma.ecore.impl.MultiResourceEObject; import org.eclipse.epf.uma.ecore.util.OppositeFeature; import org.eclipse.epf.uma.util.AssociationHelper; import org.eclipse.epf.uma.util.Scope; import org.eclipse.epf.uma.util.UserDefinedTypeMeta; /** * @author Jinhua Xi * @author Phong Nguyen Le * @author Weiping Lu * @since 1.0 */ public class ConfigurationHelper { public static boolean serverMode = false; private static ConfigHelperDelegate delegate; static { ConfigHelperDelegate extendedDelegate = (ConfigHelperDelegate) ExtensionHelper .getExtension(LibraryPlugin.getDefault().getId(), "configHelperDelegateExt");//$NON-NLS-1$ if (extendedDelegate == null) { delegate = new ConfigHelperDelegate(); } else { delegate = extendedDelegate; } } public static ConfigHelperDelegate getDelegate() { return delegate; } private static boolean inheritingSlotFeatures = false; public static final String ATTRIBUTE_VALUE_SEPERATOR = "<p/>"; //$NON-NLS-1$ private static boolean debug = LibraryPlugin.getDefault().isDebugging(); /** * check if the element is a ContentDescription * * @param element {@link MethodElement} * @return boolean */ public static boolean isDescriptionElement(MethodElement element) { if ( element == null ) { return false; } return (element instanceof ContentDescription || element.eContainer() instanceof ContentDescription); } /** * check if the method pacj=kage is a global package * * @param pkg {@link MethodPackage} * @return boolean */ public static boolean isGlobalPackage(MethodPackage pkg) { if (pkg == null) { if (debug) { System.out .println("ConfigurationHelper.isGlobalPackage: method package is null"); //$NON-NLS-1$ } return false; } MethodPlugin p = LibraryUtil.getMethodPlugin(pkg); if (p == null) { if (debug) { System.out .println("ConfigurationHelper.isGlobalPackage: Unable to find method plug-in for " + pkg.getName() + ": " + pkg.getGuid()); //$NON-NLS-1$ //$NON-NLS-2$ } return false; } return getDelegate().isSystemPackage(p, pkg); } /** * check if the element is in the configuration * * @param element * @param config * @return */ public static boolean inConfig(MethodElement element, MethodConfiguration config) { return inConfig(element, config, true); } /** * check if the element is in the configuration * * @param element * @param config * @return */ public static boolean inConfig(MethodElement element, MethodConfiguration config, boolean checkSubtracted) { return inConfig(element, config, checkSubtracted, true); } /** * check if the element is in the configuration * * @param element * @param config * @return */ public static boolean inConfig(MethodElement element, MethodConfiguration config, boolean checkSubtracted, boolean checkBase) { if (!isOwnerSelected(element, config, checkSubtracted)) { return false; } //Bug 207429 - Configration: Warring info should shown when deselect the replaced element // for configuration closure checking, the missing base should be reported // so the element been checked still treated as in config // added the checkBase flag to ignore the base checking // for configuration realization, this flag should be set to true // so the replacer missing base is not included in the config. // if the element is a repalcer, and it's base element has more than one // replacer // none of the replacers should be included into the configuration if (checkBase && (element instanceof VariabilityElement) ) { VariabilityElement ve = (VariabilityElement) element; if (isReplacer(ve)) { VariabilityElement base = ve.getVariabilityBasedOnElement(); if (inConfig(base, config)) { // // Invalid hotspot created for locally replaced activity in activity diagram // // this is because the activity has more than one local replacers // // in version 7.0, local replacement is modeled the same way as nomal replacement // // we need to ignore this checking for activity // if ( element instanceof Activity ) { // return true; // } for (Iterator it = AssociationHelper.getImmediateVarieties( base).iterator(); it.hasNext();) { VariabilityElement e = (VariabilityElement) it.next(); if ((e != element) && (e.getVariabilityType() == VariabilityType.REPLACES) && isOwnerSelected(e, config, checkSubtracted)) { if (debug) { System.out .println("ConfigurationHelper.inConfig: Ignoring replacing element '" + LibraryUtil.getTypeName(element) + "' since its base element has more than one replacer in the configuration"); //$NON-NLS-1$ //$NON-NLS-2$ } return false; } } } else { return false; // base must be in the configuration } } } return true; } private static boolean isOwnerSelected(MethodElement element, MethodConfiguration config, boolean checkSubtracted) { return getDelegate().isOwnerSelected(element, config, checkSubtracted); } /** * is the element a contributor? * @param element * @return boolean */ public static boolean isContributor(VariabilityElement element) { if (element == null || element.getVariabilityBasedOnElement() == null) return false; return element.getVariabilityType() == VariabilityType.CONTRIBUTES; } /** * is the element a replacer? * @param element * @return boolean */ public static boolean isReplacer(VariabilityElement element) { if (element == null || element.getVariabilityBasedOnElement() == null) return false; return element.getVariabilityType() == VariabilityType.REPLACES; } /** * is "b" an ancestor of "a" through a "contribute chain" relationship * @param a * @param b * @return */ public static boolean contrubuteChain(VariabilityElement a, VariabilityElement b) { VariabilityElement element = a; while (element != null) { if (element.getVariabilityType() != VariabilityType.CONTRIBUTES) { return false; } element = element.getVariabilityBasedOnElement(); if (element == null) { return false; } if (element == b) { return true; } } return false; } /** * is the element a extend-replacer? * @param element * @return boolean */ public static boolean isExtendReplacer(VariabilityElement element) { if (element == null || element.getVariabilityBasedOnElement() == null) return false; return element.getVariabilityType() == VariabilityType.EXTENDS_REPLACES; } /** * is the element an extender? * @param element * @return boolean */ public static boolean isExtender(VariabilityElement element) { if (element == null || element.getVariabilityBasedOnElement() == null) return false; return element.getVariabilityType() == VariabilityType.EXTENDS; } /** * get the replacer of the element in the configuration. Only one replacer * is allowed. If more than one replacer is found, then none of them will be * returned. * * @param element * VariabilityElement the element * @param config * MethodConfiguration * @return VariabilityElement the replacer if there is one and ONLY one, * null otherwise */ public static VariabilityElement getReplacer(VariabilityElement element, MethodConfiguration config) { VariabilityElement ve = null; // this will get all replacers recursively. we only need the immediate // ones // for(Iterator iterator = TngUtil.getGeneralizers(element, // VariabilityType.REPLACES_LITERAL); iterator.hasNext();) for (Iterator it = AssociationHelper.getImmediateVarieties(element) .iterator(); it.hasNext();) { VariabilityElement e = (VariabilityElement) it.next(); if ( e == null || !inConfig(e, config) ) { continue; } VariabilityType type = e.getVariabilityType(); if ( type == VariabilityType.REPLACES || type == VariabilityType.EXTENDS_REPLACES) { if (ve != null) { if (debug) { System.out .println("ConfigurationHelper.getReplacer: Replacer ignored for element '" + LibraryUtil.getTypeName(element) + "' since it has more than one replacerin the configuration"); //$NON-NLS-1$ //$NON-NLS-2$ } return null; // if more than one replacer, return null } ve = e; } } return ve; } /** * get the immediate contributors of the element within the configuration. * If a contributor has immediate replacer, it is repalced with the replacer * * @param element * @param config * @return */ public static List getContributors(VariabilityElement element, MethodConfiguration config) { List items = new ArrayList(); if ( element == null ) { return items; } // This method get all contributors recursively, // we only need the first level // for (Iterator it = TngUtil.getContributors(element); it.hasNext(); ) for (Iterator it = AssociationHelper.getImmediateVarieties(element) .iterator(); it.hasNext();) { VariabilityElement e = (VariabilityElement) it.next(); if ((e != null) && (e.getVariabilityType() == VariabilityType.CONTRIBUTES) && inConfig(e, config)) { VariabilityElement replacer = getReplacer(e, config); if (replacer != null) { items.add(replacer); } else { items.add(e); } } } if (element instanceof Activity) { Comparator<MethodElement> comparator = getContributorComparator(items); Collections.sort(items, comparator); } return items; } private static Comparator<MethodElement> getContributorComparator(List<MethodElement> contributors) { for (MethodElement contributor : contributors) { if (! isRefineRuleSyntax(contributor)) { Comparator<MethodElement> comparator = new Comparator<MethodElement>() { public int compare(MethodElement object1, MethodElement object2) { PropUtil propUtil = PropUtil.getPropUtil(); String v1 = propUtil.getContributionOrder(object1); if (v1 == null) { v1 = "";//$NON-NLS-1$ } String v2 = propUtil.getContributionOrder(object2); if (v2 == null) { v2 = "";//$NON-NLS-1$ } if (v1.length() == 0) { return v2.length() == 0 ? 0 : 1; } else if (v2.length() == 0) { return v1.length() == 0 ? 0 : -1; } return v1.compareTo(v2); } public boolean equals(Object object) { return this == object; } }; return comparator; } } Comparator<MethodElement> comparator = new Comparator<MethodElement>() { public int compare(MethodElement object1, MethodElement object2) { PropUtil propUtil = PropUtil.getPropUtil(); String v1 = propUtil.getContributionOrder(object1); if (v1 == null) { v1 = "";//$NON-NLS-1$ } String v2 = propUtil.getContributionOrder(object2); if (v2 == null) { v2 = "";//$NON-NLS-1$ } if (v1.length() == 0) { return v2.length() == 0 ? 0 : 1; } else if (v2.length() == 0) { return v1.length() == 0 ? 0 : -1; } String[] str1 = v1.split("\\."); //$NON-NLS-1$ String[] str2 = v2.split("\\."); //$NON-NLS-1$ int sz = Math.min(str1.length, str2.length); for (int i = 0; i < sz; i++) { int n1 = 0; int n2 = 0; try { n1 = Integer.parseInt(str1[i]); } catch (Exception e) { } try { n2 = Integer.parseInt(str2[i]); } catch (Exception e) { } if (n1 != n2) { return n1 < n2 ? -1 : 1; } } if (str1.length == str2.length ) { return 0; } return str1.length < str2.length ? -1 : 1; } public boolean equals(Object object) { return this == object; } }; return comparator; } private static boolean isRefineRuleSyntax(MethodElement contributor) { PropUtil propUtil = PropUtil.getPropUtil(); String value = propUtil.getContributionOrder(contributor); if (value == null || value.length() == 0) { return true; } boolean dotIsAllowed = false; for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); if (c == '.') { if (!dotIsAllowed) { return false; } dotIsAllowed = false; } else if ('9' >= c && c >= '0') { dotIsAllowed = true; } else { return false; } } return true; } public static List getExtenders(VariabilityElement element, MethodConfiguration config) { List items = new ArrayList(); if ( element == null ) { return items; } for (Iterator it = AssociationHelper.getImmediateVarieties(element) .iterator(); it.hasNext();) { VariabilityElement e = (VariabilityElement) it.next(); if ((e != null) && (e.getVariabilityType() == VariabilityType.EXTENDS) && inConfig(e, config)) { items.add(e); } } return items; } public static Set<VariabilityElement> getLocalContributersAndReplacers(VariabilityElement element, MethodConfiguration config) { Set<VariabilityElement> items = new HashSet<VariabilityElement>(); if ( element == null ) { return items; } for (Iterator it = AssociationHelper.getImmediateVarieties(element) .iterator(); it.hasNext();) { VariabilityElement e = (VariabilityElement) it.next(); if ((e != null) && (isLocalContributerOrReplacer(e)) && inConfig(e, config)) { items.add(e); } } return items; } private static boolean isLocalContributerOrReplacer( VariabilityElement ve) { VariabilityType type = ve.getVariabilityType(); return type == VariabilityType.LOCAL_CONTRIBUTION || type == VariabilityType.LOCAL_REPLACEMENT; } public static boolean canShow(MethodElement element, MethodConfiguration config) { return canShow(element,config, true); } /** * element can't show in the configuration tree if 1. the element is not in * the configuration 2. the element is a contribution to another element 3. * if the element is a replacer to a 3. the element has a replacement * element in the configuration * * @param element * @param config * @return boolean */ public static boolean canShow(MethodElement element, MethodConfiguration config, boolean checkSubtracted) { if (element == null) { return false; } if (!inConfig(element, config, checkSubtracted)) { return false; } // // if it;s an activity, return since contributors are local contribution and needs to be shown // if (element instanceof Activity) { // return true; // } // ///////////////////////////////////////////////////////////////////////////////////////////////// // // this is not needed any more since the suppression state is determined by the activity adaptor factory // // just leave it here for now since it does not hurt. take it away in next release // // NO, we still need to keep this to check the suppression of descriptors referenced by another descriptor. // for example, when displaying a TD page, we need to handle the suppression of the referenced WPDs and RDs. // 00395278 - Browsing TD with suppressed RD/WPD under it -- suppressed ones still showing // Note: this does not handle the case when the descriptor is with an inherited activity. // in that case, the suppression need to be determined by the activity path. TODO Boolean supressed = element.getSuppressed(); if (supressed != null && supressed.booleanValue() == true) { return false; } // ///////////////////////////////////////////////////////////////////////////////////////////////// if ( element instanceof VariabilityElement) { if ( !canShowByCheckingVE((VariabilityElement) element,config) ) { return false; } } return true; } /** * * @param e * @param config * @return */ public static boolean canShowByCheckingVE(VariabilityElement e, MethodConfiguration config){ // if this is an extender, always show, even though it extends a // contributor if (isExtender(e)) { return true; } if (isContributor(e) || getReplacer(e, config) != null) { return false; } // for activity, don't show the ones that contains contributors // the resaon for this is to simplify the logic. // assuming that user uses this activity to contribute to other activities // so that part should not be involved in the navigation // // Jinhua Xi, 07/14/06, if ( (e instanceof Activity) && hasContributor((Activity)e) ) { return false; } while ((e != null) && (isReplacer(e) || isExtendReplacer(e))) { e = (VariabilityElement) e.getVariabilityBasedOnElement(); if (isContributor(e)) { return false; } } return true; } /** * get the name of the element in the configuration. 1. if it's a * contributor, show the name of the base element 2. if it has a * replacemenet, show the name of the replacement element * * @param element * @param config * @return String */ public static String getName(MethodElement element, MethodConfiguration config) { if (element instanceof VariabilityElement) { VariabilityElement e = (VariabilityElement) element; if (isContributor(e)) { return getName(e.getVariabilityBasedOnElement(), config); } else { VariabilityElement rep = getReplacer(e, config); if (rep != null) { return getName(rep, config); } } } return element.getName(); } /** * get the presentation name for an element in the configuration * @param element * @param config * @return String */ public static String getPresentationName(MethodElement element, MethodConfiguration config) { // [Bug 196399] P-name is not inherited from its base element in an extending element String name = null; name = element.getPresentationName(); if ( StrUtil.isBlank(name) && (element instanceof VariabilityElement) ) { EStructuralFeature f = UmaPackage.eINSTANCE.getVariabilityElement_VariabilityBasedOnElement(); ElementRealizer r = DefaultElementRealizer.newElementRealizer(config); MethodElement me = element; Set<MethodElement> seens = new HashSet<MethodElement>(); do { VariabilityElement oldMe = (VariabilityElement) me; me = (DescribableElement)ConfigurationHelper.calc01FeatureValue(me, f, r); if ( me == null ) { break; } else if (oldMe == me || seens.contains(me)) { me = oldMe.getVariabilityBasedOnElement(); if (me == null) { break; } } name = ((DescribableElement)me).getPresentationName(); if (seens.contains(me)) { //to prevent loop in case such as break; //both extend-replacer and base have empty pres name } seens.add(oldMe); seens.add(me); } while ( StrUtil.isBlank(name) ); } if ( StrUtil.isBlank(name) ) { name = TngUtil.getPresentationName(element); } return name; } /** * get the variability element owner. If the element is a * VariabilityElement, return itself otherwise, find it's owner. For * example, a ContentDescriotion object is ownered by a VariabilityElement * * @param e * MethodElement * @return VariabilityElement */ public static VariabilityElement getVariableOwner(MethodElement e) { if (e instanceof VariabilityElement) { return (VariabilityElement) e; } else if (e instanceof ContentDescription) { // return AssociationHelper.getOwner( (ContentDescription)e ); EObject eObj = e.eContainer(); if (eObj instanceof VariabilityElement) { return (VariabilityElement) eObj; } } return null; } /** * check if the feature value is mergable or not * @param feature * @return boolean */ public static boolean isMergableAttribute(EStructuralFeature feature) { if (!feature.getEType().getInstanceClassName().equals( "java.lang.String")) //$NON-NLS-1$ { return false; } // feature id is not globally unique, can't do a switch here // compare the acture featrue instead /* * switch ( feature.getFeatureID() ) { case * UmaPackage.METHOD_ELEMENT__GUID: case * UmaPackage.METHOD_ELEMENT__NAME: * Contributing a Unique ID for work product renders * bad html // don't merge Unique ID: case * UmaPackage.WORK_PRODUCT_DESCRIPTION__EXTERNAL_ID: return false; } */ if (feature == UmaPackage.eINSTANCE.getMethodElement_Guid() || feature == UmaPackage.eINSTANCE.getNamedElement_Name() || feature == UmaPackage.eINSTANCE .getContentDescription_ExternalId() || feature == UmaPackage.eINSTANCE.getMethodElement_PresentationName()) { return false; } return true; } /** * is attribute feature value? * @param feature * @return boolean */ public static boolean isAttributeFeature(EStructuralFeature feature) { return (feature.getEType() instanceof EAttribute); } /** * is this a to-one feature? * @param feature * @return boolean */ public static boolean is01Feature(EStructuralFeature feature) { return (feature.getEType() instanceof EClass) && !feature.isMany(); } /** * is this a to-many feature? * @param feature * @return boolean */ public static boolean is0nFeature(EStructuralFeature feature) { return (feature.getEType() instanceof EClass) && feature.isMany(); } /** * calculate the value of the specified element and feature * * @param element * @param feature * @param config * @param values * The List of values of the feature. if the feature is a 0..1 * association, the List holds a single value if any for * reference list feature, it's a list of references for * attribute feature, it's a list of attribute values to be * mergered for 0..1 association, the list may contain 1 value. */ // private static void calculateFeature(MethodElement element, // EStructuralFeature feature, MethodConfiguration config, // List values, ElementRealizer realizer) { // calculateFeature(element, null, feature, config, values, realizer); // } private static void calculateFeature(MethodElement element, MethodElement OwnerElement, EStructuralFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { TypeDefUtil typeDefUtil = TypeDefUtil.getInstance(); // make sure this is a valid feature // for example, if an activity contributes to a Capability Pattern, // some CapabilityPattern specific feature may not be a valid feature for the Activity // List features = element.getInstanceProperties(); List features = LibraryUtil.getStructuralFeatures(element, true); if ( !features.contains(feature)) { if (element instanceof Practice) { PracticePropUtil practicePropUtil = PracticePropUtil.getPracticePropUtil(); Practice practice = (Practice) element; UserDefinedTypeMeta meta = practicePropUtil.getUdtMeta(practice); if (meta == null || ! meta.isQualifiedRefernce((EReference) feature)) { return; } } else { return; } } // EClassifier type = feature.getEType(); VariabilityElement ve = getVariableOwner((OwnerElement == null) ? element : OwnerElement); // Object value = element.eGet(feature); Object value = typeDefUtil.eGet(element, feature); values.add(ve, value); if (config == null || config instanceof Scope) { return; } // realize the variability relationship if (ve == null) { return; } // according to Peter, the realization should be always top down. // i.e realize the base first, then include the contributions __mergeBase(element, ve, feature, config, values, realizer); if (element instanceof FulfillableElement) { if (feature != UmaPackage.eINSTANCE .getFulfillableElement_Fulfills()) { mergeSlotFeatureValues((FulfillableElement) element, feature, config, values, realizer); } } else if (OwnerElement instanceof FulfillableElement) { mergeSlotFeatureValues(element, (FulfillableElement) OwnerElement, feature, config, values, realizer); } if (realizer != null) { realizer.addExtraFeatureValues(element, feature, values); } if (!is01Feature(feature) || (values.size() == 0) ) { __mergeContributors(element, ve, feature, config, values, realizer); } } // public static List<FulfillableElement> calcFulfillableElement_Fulfills(FulfillableElement element, // MethodConfiguration config); //Change the signature and use a try/catch block in case there is any regression with some corner case. public static List<FulfillableElement> calcFulfillableElement_Fulfills(FulfillableElement element, ElementRealizer realizer) { try { return calcFulfillableElement_Fulfills_(element, realizer); } catch (Exception e) { return Collections.EMPTY_LIST; } } private static List<FulfillableElement> calcFulfillableElement_Fulfills_(FulfillableElement element, ElementRealizer realizer) { List<FulfillableElement> resultList = new ArrayList<FulfillableElement>(); MethodConfiguration config = realizer.getConfiguration(); // ElementRealizer realizer = DefaultElementRealizer.newElementRealizer(config); Object fullfillsObj = calc0nFeatureValue(element, UmaPackage.eINSTANCE.getFulfillableElement_Fulfills(), realizer); if (! (fullfillsObj instanceof List)) { return resultList; } EStructuralFeature feature = UmaPackage.eINSTANCE.getFulfillableElement_Fulfills(); for (FulfillableElement slot : (List<FulfillableElement>) fullfillsObj) { slot = (FulfillableElement) getCalculatedElement(slot, config); if (slotMatching(slot, element, realizer)) { resultList.add(slot); } } if (resultList.size() > 1) { Comparator comparator = PresentationContext.INSTANCE.getPresNameComparator(); Collections.<FulfillableElement>sort(resultList, comparator); } return resultList; } private static void mergeSlotFeatureValues(FulfillableElement element, EStructuralFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { if (!inheritingSlotFeatures) { return; } if (feature == UmaPackage.eINSTANCE.getFulfillableElement_Fulfills()) { return; } if (!(element instanceof WorkProduct)) { return; } if (values.size() > 0) { return; } List<FulfillableElement> slots = calcFulfillableElement_Fulfills(element, realizer); for (FulfillableElement slot : slots) { if (slot instanceof WorkProduct) { slot = (FulfillableElement) getCalculatedElement(slot, config); calculateFeature(slot, null, feature, config, values, realizer); } } } private static void mergeSlotFeatureValues(MethodElement element, FulfillableElement OwnerElement, EStructuralFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { if (!inheritingSlotFeatures) { return; } if (! (element instanceof ContentDescription)) { return; } if (!(OwnerElement instanceof WorkProduct)) { return; } if (values.size() > 0) { return; } List<FulfillableElement> slots = calcFulfillableElement_Fulfills(OwnerElement, realizer); for (FulfillableElement slot : slots) { if (slot instanceof WorkProduct) { slot = (FulfillableElement) getCalculatedElement(slot, config); ContentDescription slotOwnedElement = slot.getPresentation(); calculateFeature(slotOwnedElement, slot, feature, config, values, realizer); } } } private static void mergeSlotOppositeFeatureValues(FulfillableElement element, OppositeFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { if (!inheritingSlotFeatures) { return; } if (feature == AssociationHelper.FulFills_FullFillableElements) { return; } if (!(element instanceof WorkProduct)) { return; } if (values.size() > 0) { return; } List<FulfillableElement> slots = calcFulfillableElement_Fulfills(element, realizer); for (FulfillableElement slot : slots) { slot = (FulfillableElement) getCalculatedElement(slot, config); calculateOppositeFeature(slot, feature, realizer, values); } } public static List<FulfillableElement> calcFulfills_FulfillableElement( FulfillableElement slot, MethodConfiguration config) { List<FulfillableElement> resultList = new ArrayList<FulfillableElement>(); ElementRealizer realizer = DefaultElementRealizer .newElementRealizer(config); List fulfillingList = calc0nFeatureValue(slot, AssociationHelper.FulFills_FullFillableElements, realizer); for (FulfillableElement element : (List<FulfillableElement>) fulfillingList) { element = (FulfillableElement) getCalculatedElement(element, config); if (slotMatching(slot, element, realizer)) { resultList.add(element); } } if (resultList.size() > 1) { Comparator comparator = PresentationContext.INSTANCE.getPresNameComparator(); Collections.<FulfillableElement>sort(resultList, comparator); } return resultList; } private static boolean slotMatching(FulfillableElement slot, FulfillableElement element, ElementRealizer realizer) { if (slot == null || !slot.getIsAbstract()) { return false; } if (realizer != null) { return realizer.slotMatching(slot, element); } return true; } private static void __mergeBase(MethodElement element, VariabilityElement ve, EStructuralFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { // if the element is an extended element, get the base element's // properties if needed boolean extendReplace = isExtendReplacer(ve) || ElementRealizer.isExtendReplaceEnabled() && isReplacer(ve); boolean isExtender = isExtender(ve); if (extendReplace && PropUtil.getPropUtil().isCustomize(ve)) { return; } if (isExtender || extendReplace) { boolean mergebase = false; if (is0nFeature(feature)) { mergebase = true; if ( extendReplace || isExtender && ElementRealizer.ignoreBaseToManyAssociations()) { mergebase = (values.size() == 0); } } else if (is01Feature(feature)) { mergebase = (values.size() == 0); } else { mergebase = (isMergableAttribute(feature) && (values.size() == 0)); } if (mergebase) { // Authoring: Extending a base that has been // replaced, does not extend the replacement // need to get the realized element, // the base element might be replaced by another one, // or might be a contributor to another base MethodElement e = ve.getVariabilityBasedOnElement(); if ( !extendReplace ) { e= getCalculatedElement(e, config); } MethodElement o = e; // if it's a containment feature, such as sub-artifacts // the base should not be the container // 162154 - Check circular references with parent-/sub-artifacts and practices/sub-practices if ( isContainmentFeature(feature) ) { List containers = getContainers(ve, config); if (containers.contains(e) ) { mergebase = false; } } if (mergebase && (ve != e) && inConfig(e, config)) { // if the current element is a description, // get the the description object of the base if (element instanceof ContentDescription) { try { e = ((DescribableElement) e).getPresentation(); } catch (Exception e1) { e1.printStackTrace(); } } calculateFeature(e, o, feature, config, values, realizer); // for extender, we need to re-sort the steps based on the // extender defined order if ((ve instanceof ContentElement) && (feature == UmaPackage.eINSTANCE .getContentDescription_Sections())) { orderSections((ContentElement) ve, (List)values.getValue()); } } } } } private static void __mergeContributors(MethodElement element, VariabilityElement ve, EStructuralFeature feature, MethodConfiguration config, FeatureValue values, ElementRealizer realizer) { boolean mergeable = true; if ( isAttributeFeature(feature) && !isMergableAttribute(feature) ) { mergeable = false; } if ( mergeable ) { // if the element has contributors in the configuration, get the // reference properties // if a contributor has replacer, it's replacer is used List items = getContributors(ve, config); if (items != null && items.size() > 0) { for (Iterator it = items.iterator(); it.hasNext();) { MethodElement e = (MethodElement) it.next(); MethodElement o = e; // the owner // if the current element is a description, // get the the description object of the contributor if (element instanceof ContentDescription) { e = ((DescribableElement) e).getPresentation(); } calculateFeature(e, o, feature, config, values, realizer); } } } } /** * calculate the reflist for the specified element and OppositeFeature * * @param element * @param feature * OppositeFeature * @param realizer ElementRealizer * @param values * The List of values of the feature. for reference list feature, * it's a list of references for attribute feature, it's a list * of attribute values to be mergered */ private static void calculateOppositeFeature(MethodElement element, OppositeFeature feature, ElementRealizer realizer, FeatureValue values) { calculateOppositeFeature(element, feature, true, false, realizer, values); } /** * calculate the reflist for the specified element and OppositeFeature * * @param element * @param feature * OppositeFeature * @param realizer ElementRealizer * @param values * The List of values of the feature. for reference list feature, * it's a list of references for attribute feature, it's a list * of attribute values to be mergered */ private static void calculateOppositeFeature(MethodElement element, OppositeFeature feature, boolean mergeReplacerBase, boolean mergeExtenderBase, ElementRealizer realizer, FeatureValue values) { // must be a MultiResourceEObject if (!(element instanceof MultiResourceEObject)) { return; } MethodConfiguration config = realizer.getConfiguration(); VariabilityElement ve = getVariableOwner(element); Object value = ((MultiResourceEObject) element) .getOppositeFeatureValue(feature); values.add(ve, value); if (element instanceof VariabilityElement && config != null) { VariabilityElement ce = (VariabilityElement) element; // if the element has contributors in the configuration, get the // reference properties List items = getContributors(ce, config); if (items != null && items.size() > 0) { for (Iterator it = items.iterator(); it.hasNext();) { MethodElement e = (MethodElement) it.next(); calculateOppositeFeature(e, feature, mergeReplacerBase, mergeExtenderBase, realizer, values); } } // if the element is a replacer of a base element, // get the base element's properties // only cover 01 or 0m references // attributes can't be opposite feature // replaced element does not show incoming // relationships // imcoming relationships are represented by opposite feature // so keep the references to the base element // Inconsistency between Published Work Product: Workload Analysis Page and Referenced Pages // this is from the base of the extender. // incoming associations from the base should be discarded for extenders boolean mergebase = false; boolean isExtender = isExtender(ce); boolean isReplacer = isReplacer(ce); boolean isExtendReplacer = isExtendReplacer(ce) || ElementRealizer.isExtendReplaceEnabled() && isReplacer; // //This is a conservative fix for "Extends-replace displine rendered wrong in conf tree view" // if (isExtendReplacer(ce) && realizer.getClass() == DefaultElementRealizer.class) { // if (feature == AssociationHelper.Discipline_DisciplineGroupings) { // isReplacer = true; // } // if (feature == AssociationHelper.RoleSet_RoleSetGrouppings) { // isReplacer = true; // } // } // extenderReplacer behaves like replacer when realizing incoming associations // Bug 199694 - Extends-Replace ignores incoming relationships of contributer if ( isExtendReplacer ) { isReplacer = true; } if (isReplacer) { mergebase = mergeReplacerBase && ((value instanceof List) || (values.size() == 0)); } else if (isExtender) { mergebase = mergeExtenderBase; } if (mergebase) { // resolve the base contributor to the base if i am not a // replacer // don't resolve the contributors to the base if i am a // replacer, // the call is coming from the base. So if resolve to base again // will cause deadlock. // don't resolve to the replacer since we need to carry down all // the incoming 0n associations from base // actually should resolve to replacer if i am not a replacer // (i.e. i am an entender) // this handles the senario: G2 replaces G1 and G3 extends G1 ElementRealizer realizer2 = DefaultElementRealizer.newElementRealizer(config, (!isReplacer), (!isReplacer)); MethodElement e = getCalculatedElement(ce .getVariabilityBasedOnElement(), realizer2); // if the base element resolved to null, // this is because canShow() don't allow replaced element to show. // we don't want to take the risk to fix ElementRealizer // so fix here since 7.0.1_ifix1, // Jinhua Xi, 4/17/06 if ( e == null ) { e = ce.getVariabilityBasedOnElement(); } if ((e != ce) && inConfig(e, config)) { calculateOppositeFeature(e, feature, mergeReplacerBase, mergeExtenderBase, realizer, values); } } if (element instanceof FulfillableElement) { mergeSlotOppositeFeatureValues((FulfillableElement) element, feature, config, values, realizer); } } } /** * calculate the elements in the list, and returns a new list of unique * elements * * @param elements * @param config * @return List */ public static List getCalculatedElements(List elements, MethodConfiguration config) { return getCalculatedElements(elements, DefaultElementRealizer.newElementRealizer(config) ); } /** * calculate the elements in the list, and returns a new list of unique * elements * * @param elements * @param realizer ElementRealizer * @return List */ public static List getCalculatedElements(List elements, ElementRealizer realizer ) { // calculate each element in the list and return a new list of elements List values = new ArrayList(); for (Iterator it = elements.iterator(); it.hasNext();) { MethodElement e = (MethodElement) it.next(); e = ConfigurationHelper.getCalculatedElement(e, realizer); if ((e != null) && (!values.contains(e))) { values.add(e); } } return values; } /** * calculate the element based on tle configuration. If nothing can be * shown, return null. * * @param element * @param config * @return */ public static MethodElement getCalculatedElement(MethodElement element, MethodConfiguration config) { ElementRealizer realizer = DefaultElementRealizer.newElementRealizer(config, true, true); return getCalculatedElement(element, realizer); } public static MethodElement getCalculatedElement(MethodElement element, ElementRealizer realizer) { MethodElement e = element; MethodElement e2; while ((e2 = realizer.realize(e)) != e) { e = e2; } return e; } /** * get the calculated 0..1 feature value of the specipied element and * feature * * @return MethodElement */ public static MethodElement calc01FeatureValue(MethodElement element, EStructuralFeature feature, ElementRealizer realizer) { return calc01FeatureValue(element, null, feature, realizer); } /** * get the calculated 0..1 feature value of the specipied element and * feature * * @return MethodElement */ public static MethodElement calc01FeatureValue(MethodElement element, MethodElement ownerElement, EStructuralFeature feature, ElementRealizer realizer) { // presentation object feature should never be realized. always keep // it's own value Object v = element.eGet(feature); if (v instanceof ContentDescription) { return (MethodElement) v; } ToOneFeatureValue values = new ToOneFeatureValue(element, ownerElement, feature, realizer); calculateFeature(element, ownerElement, feature, realizer.getConfiguration(), values, realizer); // if (values.size() > 0) { // v = (MethodElement) values.get(0); // if (v instanceof MethodElement) { // return getCalculatedElement((MethodElement) v, realizer.getConfiguration()); // } // } return (MethodElement)values.getValue(); } /** * is this feature for containd children? such as artifact's contained artifact. * @param feature * @return boolean */ public static boolean isContainmentFeature(EStructuralFeature feature) { return feature == UmaPackage.eINSTANCE.getArtifact_ContainedArtifacts() || feature == UmaPackage.eINSTANCE.getPractice_SubPractices(); } /** * check if the element allow contained element * @param element * @return boolean */ public static boolean isContainmentElement(Object element) { return element instanceof Artifact || element instanceof Practice; } private static List getContainers(MethodElement element, MethodConfiguration config) { List items = new ArrayList(); EObject o = element; while ((o != null) && ((o = o.eContainer()) != null) && o.getClass().isInstance(element)) { if (o instanceof VariabilityElement) { o = getCalculatedElement((VariabilityElement) o, config); } if ((o != null) && !items.contains(o)) { items.add(o); } } return items; } /** * get the 01 opposite feature (if any) for the given feature. returns null * if no such feature * * @param feature * EStructuralFeature * @return OppositeFeature the 01 opposite feature of the given feature, * null if no such thing */ public static OppositeFeature get01OppositeFeature( EStructuralFeature feature) { // since 1.0m4, these are not 01 feature any more // if (feature == UmaPackage.eINSTANCE.getDiscipline_Tasks()) { // return AssociationHelper.Task_Discipline; // } else if (feature == UmaPackage.eINSTANCE.getRole_ResponsibleFor()) { // return AssociationHelper.WorkProduct_ResponsibleRole; // } // if ( feature == UmaPackage.eINSTANCE.getDomain_WorkProducts() ) { // return AssociationHelper.WorkProduct_Domains; // } return null; } /** * get the target feature for the opposite feature if the target feature is a to-One feature, * otherwise, return null. * @param oFeature * @return EStructuralFeature */ public static EStructuralFeature get01Feature(OppositeFeature oFeature) { /* if ( oFeature == AssociationHelper.Role_Primary_Tasks || oFeature == AssociationHelper.RoleDescriptor_PrimaryTaskDescriptors ) { return oFeature.getTargetFeature(); }*/ return null; } /** * get the calculated 0..n feature value of the specipied element, it's * owner element and feature * * @param element {@link MethodElement} * @param feature {@link EStructuralFeature} * @param realizer {@link ElementRealizer} * @return List a list of {@link MethodElement} */ public static List calc0nFeatureValue(MethodElement element, EStructuralFeature feature, ElementRealizer realizer) { TypeDefUtil typeDefUtil = TypeDefUtil.getInstance(); if (realizer == null) { Object value = typeDefUtil.eGet(element, feature); return value instanceof List ? (List) value : null; } if (realizer != null && realizer.getConfiguration() instanceof Scope) { // Object value = element.eGet(feature); Object value = typeDefUtil.eGet(element, feature); if (value instanceof List) { List listValue = new ArrayList((List) value); for (int i = 0; i < listValue.size(); i++) { if (listValue.get(i) instanceof MethodElement) { MethodElement e0 = (MethodElement) listValue.get(i); MethodElement e1 = realizer.realize(e0); if (e1 != null && e1 != e0) { listValue.set(i, e1); } } else { break; } } return listValue; } return null; } return calc0nFeatureValue(element, null, feature, realizer); } /** * get the calculated 0..n feature value of the specipied element and * feature. if the opposite feature on the other end is a to-one feature, * the feature value item can't be in the value list unless it's opposite * feature value is the current element. For example, for discipline_tasks, * the tasks can be selected if and ONLY if the task's task_discipline * opposite feature value is the current discipline * * @param element MethodElement * @param ownerElement {@link MethodElement} * @param feature {@link EStructuralFeature} * @param realizer {@link ElementRealizer} * @return List a list of {@link MethodElement} */ public static List calc0nFeatureValue(MethodElement element, MethodElement ownerElement, EStructuralFeature feature, ElementRealizer realizer) { List ret = calc0nFeatureValue_(element, ownerElement, feature, realizer); if (ret != null && !ret.isEmpty() && (element instanceof Task) && feature == UmaPackage.eINSTANCE.getTask_OptionalInput()) { List mInputs = calc0nFeatureValue_(element, ownerElement, UmaPackage.eINSTANCE.getTask_MandatoryInput(), realizer); if (mInputs != null && ! mInputs.isEmpty()) { ret.removeAll(mInputs); } } return ret; } private static List calc0nFeatureValue_(MethodElement element, MethodElement ownerElement, EStructuralFeature feature, ElementRealizer realizer) { List v = null; MethodConfiguration config = realizer.getConfiguration(); // Wrong "modifies" information published in team allocation view for small configuration // need to manually calculate the modify features // can't rely on the uma model since that is not configuration specific. // role modifies product means: // role performs on tasks, and tasks produce workproducts as output // so handle these scenarios as special cases if ( element instanceof Role && feature == UmaPackage.eINSTANCE.getRole_Modifies() ) { // List v2 = new ArrayList(); // calculateOppositeFeature(element, AssociationHelper.Role_Primary_Tasks, realizer, v2); // if ( v2.size() > 0 ) { // for (Iterator it = v2.iterator(); it.hasNext(); ) { // MethodElement e = (MethodElement)it.next(); // calculateFeature(e, ownerElement, UmaPackage.eINSTANCE.getTask_Output(), config, v, realizer); // } // } v = calcModifiedWorkProducts((Role)element, ownerElement, realizer); }else if ( element instanceof RoleDescriptor && feature == UmaPackage.eINSTANCE.getRoleDescriptor_Modifies() ) { // List v2 = new ArrayList(); // calculateOppositeFeature(element, AssociationHelper.RoleDescriptor_PrimaryTaskDescriptors, realizer, v2); // if ( v2.size() > 0 ) { // for (Iterator it = v2.iterator(); it.hasNext(); ) { // MethodElement e = (MethodElement)it.next(); // calculateFeature(e, ownerElement, UmaPackage.eINSTANCE.getTaskDescriptor_Output(), config, v, realizer); // } // } v = calcModifiedWorkProductDescriptors((RoleDescriptor)element, ownerElement, realizer); } else { ToManyFeatureValue fv = new ToManyFeatureValue(element, ownerElement, feature, realizer); calculateFeature(element, ownerElement, feature, config, fv, realizer); v = (List)fv.getValue(); } List values = getCalculatedElements(v, realizer); if (values.contains(element)) { values.remove(element); } // * if the opposite feature on the other end is a to-one feature, // * the feature value item can't be in the value list unless it's // opposite feature value is the current element. // * For example, for discipline_tasks, the tasks can be selected // * if and ONLY if the task's task_discipline opposite feature value is // the current discipline OppositeFeature of = get01OppositeFeature(feature); if (of != null) { int i = 0; while (i < values.size()) { MethodElement o = (MethodElement) values.get(i); // calculate it's opposite feature value, the value must be the // given element // otherwise, remove it // note: don't use the current realizer // use the default realizer since we need to realize the element in the default way // 158924 - wrong categories in configuration view // workaround to allow show/hide subtracted elements ElementRealizer r = DefaultElementRealizer.newElementRealizer(config); r.setShowSubtracted(realizer.showSubtracted()); MethodElement oo = calc01FeatureValue(o, of, r); if (oo != element) { values.remove(i); } else { i++; } } } // containment feature value should not contain the owner element or its // parents // for example, artifact_containedArtifacts should not be the artifact // itself or its parents if (isContainmentFeature(feature)) { List containers = getContainers(element, config); int i = 0; while (i < values.size()) { Object o = (Object) values.get(i); if (o == element || containers.contains(o)) { values.remove(i); } else { i++; } } } List returnList = realizer.realize(element, feature, values); if (CategorySortHelper.needToSort(element, feature)) { Map map = MethodElementPropUtil.getMethodElementPropUtil().getExtendedPropertyMap(element, false); if (map == null || ! map.containsKey(ConfigurationFilter.isEmptyCheckLock)) { returnList = CategorySortHelper.sortCategoryElements(element, returnList.toArray(), true, feature, config); } } // the following part might not be general to all cases // so put it into the realizer return returnList; // // if the feature value is containment element such as artifact // // the child element can't show if any of the parent(s) are in the list // // Published site: Display of WPs under responsible role // if (feature.isMany() && values.size() > 0 // && isContainmentElement(values.get(0))) { // int i = 0; // while (i < values.size()) { // MethodElement o = (MethodElement) values.get(i); // // // if the container of the element is in the list, remove this // // element from the list // if (isContainerInList(o, values, config)) { // values.remove(i); // } else { // i++; // } // } // } // // // need to sort the concept and papers by type // if ((feature == UmaPackage.eINSTANCE // .getContentElement_ConceptsAndPapers()) // && (values.size() > 0)) { // List papers = new ArrayList(); // int i = 0; // while (i < values.size()) { // Object o = values.get(i); // if (o instanceof Whitepaper) { // papers.add(o); // values.remove(i); // } else { // i++; // } // } // // if (papers.size() > 0) { // values.addAll(papers); // } // } // // return values; } /** * check if the container of the element is in the list or not * * @param element * @param items * @param config * @return */ public static boolean isContainerInList(MethodElement element, List items, MethodConfiguration config) { EObject o = element; while ((o != null) && ((o = o.eContainer()) != null) && o.getClass().isInstance(element)) { if (items.contains(o)) { return true; } if (o instanceof VariabilityElement) { o = getCalculatedElement((VariabilityElement) o, config); } if ((o != null) && items.contains(o)) { return true; } } return false; } /** * get the calculated attribute feature value of the specipied element and * feature * * @param element {@link MethodElement} * @param feature {@link EStructuralFeature} * @param config {@link MethodConfiguration} * @return Object */ public static Object calcAttributeFeatureValue(MethodElement element, EStructuralFeature feature, MethodConfiguration config) { return calcAttributeFeatureValue(element, null, feature, config); } /** * get the calculated attribute feature value of the specipied element and * feature * * @param element MethodElement * @param ownerElement {@link MethodElement} * @param feature {@link EStructuralFeature} * @param config {@link MethodConfiguration} * @return Object */ public static Object calcAttributeFeatureValue(MethodElement element, MethodElement ownerElement, EStructuralFeature feature, MethodConfiguration config) { if (config instanceof Scope) { // Object value = element.eGet(feature); Object value = TypeDefUtil.getInstance().eGet(element, feature); if (value instanceof MethodElement) { ElementRealizer realizer = DefaultElementRealizer.newElementRealizer(config); value = realizer.realize((MethodElement) value); } return value; } //Inherent externalId for a extends and extends-replaces variability element if (ownerElement instanceof DescribableElement && ownerElement instanceof VariabilityElement && element instanceof ContentDescription && feature == UmaPackage.eINSTANCE .getContentDescription_ExternalId()) { VariabilityElement va = (VariabilityElement) ownerElement; ContentDescription presentation = (ContentDescription) element; while (presentation != null) { String extenalId = presentation.getExternalId(); if (extenalId != null && extenalId.trim().length() > 0) { return extenalId; } presentation = null; if (va.getVariabilityType() == VariabilityType.EXTENDS || va.getVariabilityType() == VariabilityType.EXTENDS_REPLACES) { va = va.getVariabilityBasedOnElement(); if (va != null) { presentation = ((DescribableElement) va) .getPresentation(); } } } } if (isMergableAttribute(feature)) { // merge the attribute values ElementRealizer realizer = DefaultElementRealizer.newElementRealizer(config); AttributeFeatureValue values = new AttributeFeatureValue(element, ownerElement, feature, realizer); calculateFeature(element, ownerElement, feature, config, values, realizer); // StringBuffer buffer = new StringBuffer(); // for (Iterator it = values.iterator(); it.hasNext();) { // FeatureValue av = (FeatureValue) it.next(); // if (av.text == null || av.text.toString().length() == 0) { // continue; // } // // if (feature == UmaPackage.eINSTANCE // .getMethodElement_PresentationName()) { // if (values.size() > 1) { // // something wrong here, will not happen but put test // // message here just in case // if (debug) { // System.out // .println("ConfigurationHelper.calcAttributeFeatureValue: Presentation Name get more then one entry: " + LibraryUtil.getTypeName(element)); //$NON-NLS-1$ // } // } // return av.text; // } // // if (buffer.length() > 0) { // buffer.append(ATTRIBUTE_VALUE_SEPERATOR); // } // // if (av.element == element) { // buffer.append(av.text); // } else { // String contentPath = ResourceHelper // .getElementPath((av.element instanceof ContentDescription) ? (MethodElement) av.element // .eContainer() // : av.element); // // String backPath = ResourceHelper // .getBackPath((element instanceof ContentDescription) ? ((ownerElement != null) ? ownerElement // : (MethodElement) element.eContainer()) // : element); // // buffer.append(ResourceHelper.fixContentUrlPath(av.text, // contentPath, backPath)); // } // } // // return buffer.toString(); return values.getValue(); } // return element.eGet(feature); return TypeDefUtil.getInstance().eGet(element, feature); } /** * get the calculated 0..n opposite feature value of the specipied element * and opposite feature * * @param element MethodElement * @param feature {@link EStructuralFeature} * @param realizer {@link ElementRealizer} * @return List a list of {@link MethodElement} */ public static List calc0nFeatureValue(MethodElement element, OppositeFeature feature, ElementRealizer realizer) { return calc0nFeatureValue(element, feature, true, false, realizer); } /** * get the calculated 0..n opposite feature value of the specipied element * and opposite feature * * @param element MethodElement * @param ownerElement {@link MethodElement} * @param feature {@link OppositeFeature} * @param mergeReplacerBase boolean * @param mergeExtenderBase boolean * @param realizer {@link ElementRealizer} * @return List a list of {@link MethodElement} */ public static List calc0nFeatureValue(MethodElement element, OppositeFeature feature, boolean mergeReplacerBase, boolean mergeExtenderBase, ElementRealizer realizer) { ToManyOppositeFeatureValue values = new ToManyOppositeFeatureValue(element, feature, realizer); calculateOppositeFeature(element, feature, mergeReplacerBase, mergeExtenderBase, realizer, values); List ret = (List)values.getValue(); if (feature == AssociationHelper.DescribableElement_CustomCategories) { Set<CustomCategory> set = ConfigurationHelper.getDelegate().getDynamicCustomCategories(element); if (set != null && !set.isEmpty()) { set.removeAll(ret); if (! set.isEmpty()) { ret.addAll(set); } } } return ret; } /** * get the calculated 0..1 feature value of the specipied element and * opposite feature * @param element {@link MethodElement} * @param feature {@link OppositeFeature} * @param realizer {@link ElementRealizer} * * @return MethodElement */ public static MethodElement calc01FeatureValue(MethodElement element, OppositeFeature feature, ElementRealizer realizer) { ToOneOppositeFeatureValue values = new ToOneOppositeFeatureValue(element, feature, realizer); calculateOppositeFeature(element, feature, realizer, values); // if (values.size() > 0) { // return getCalculatedElement((MethodElement) values.get(0), realizer); // } // // return null; return (MethodElement)values.getValue(); } /** * order the sections * * @param element {@link ContentElement} * @param values {@link List} */ public static void orderSections(ContentElement element, List values) { String orderingGuide = element.getOrderingGuide(); if (orderingGuide == null || orderingGuide.trim().length() == 0) { return; } SectionList slist = new SectionList(element, SectionList.STEPS_FOR_ELEMENT_AND_PARENTS); if (isSameList(values, slist)) { values.clear(); values.addAll(slist); return; } // otherwise, need to reorder the list OrderedListComparator comp = new OrderedListComparator(new ArrayList( values), slist); TreeSet s = new TreeSet(comp); s.addAll(values); values.clear(); values.addAll(s); } private static boolean isSameList(List l1, List l2) { if (l1.size() != l2.size()) { return false; } for (Iterator it = l1.iterator(); it.hasNext();) { Object o = it.next(); if (!l2.contains(o)) { return false; } } return true; } /** * calculate the copyright of the element int he configuration. Rule: 1. * contributors' copyright statment should be merged to the base 2. extended * element inherites the copyrights from the base 3. replacer don't inherite * the copyrights from the base 4. copyright elements should be unique, no * duplicate entry * * @param element * @param config * @param values */ private static void calculateCopyright(MethodElement element, MethodConfiguration config, List values) { SupportingMaterial copyright = (SupportingMaterial) getCalculatedElement( LibraryUtil.getCopyright(element), config); if (copyright != null && !values.contains(copyright)) { values.add(copyright); } VariabilityElement ve = getVariableOwner(element); if (ve == null) { return; } if (config == null) { return; } // merge copyrights of contributors List items = getContributors(ve, config); if (items != null && items.size() > 0) { for (Iterator it = items.iterator(); it.hasNext();) { MethodElement e = (MethodElement) it.next(); calculateCopyright(e, config, values); } } // if the element is an extended element, get the base element's // copyright // the base element's copyright should appear first if (isExtender(ve)) { // realize the base element first. MethodElement e = getCalculatedElement(ve .getVariabilityBasedOnElement(), config); if ((ve != e) && inConfig(e, config)) { List baseItems = new ArrayList(); calculateCopyright(e, config, baseItems); // add the base items to the begining if (baseItems.size() > 0) { // Authoring: Duplicate copyrights when 2 // elements with the same coyright are extending each other // remove the duplicate ones int i = 0; while (i < values.size()) { if (baseItems.contains(values.get(i))) { values.remove(i); } else { i++; } } values.addAll(0, baseItems); } } } } /** * get the copyright text * * @param element {@link MethodElement} * @param config {@link MethodConfiguration} * @return String */ public static String getCopyrightText(MethodElement element, MethodConfiguration config) { StringBuffer copyrights = new StringBuffer(); List items = new ArrayList(); ConfigurationHelper.calculateCopyright(element, config, items); if (items.size() > 0) { SupportingMaterial copyright; for (Iterator it = items.iterator(); it.hasNext();) { copyright = (SupportingMaterial) it.next(); // Contributing support material does not show // up in copy right // need to resolve the feature value. can't just get the value, // it may have contributors // String statement = // copyright.getPresentation().getMainDescription(); // String statement = (String) calcAttributeFeatureValue(copyright .getPresentation(), copyright, UmaPackage.eINSTANCE .getContentDescription_MainDescription(), config); if (statement != null && statement.length() > 0) { // need to fix the content for relative links. // since the link is a relative path to the // SupportingMaterial location, // need to convert to relative to the current element // so re-calcuate the back path // jxi, 06/28/05 String contentPath = ResourceHelper .getElementPath(copyright); String backPath = ResourceHelper.getBackPath(element); statement = ResourceHelper.fixContentUrlPath(statement, contentPath, backPath); if (copyrights.length() > 0) { copyrights.append("<p/>"); //$NON-NLS-1$ } copyrights.append(statement); } } } return copyrights.toString(); } /** * Gets String attribute values of an activity * * @param e Activity or it's ContentDescription * @param attrib * @param config * @return String */ public static String getActivityStringAttribute(MethodElement e, MethodElement ownerElement, EAttribute attrib, MethodConfiguration config) { if(!String.class.isAssignableFrom(attrib.getEAttributeType().getInstanceClass())) { throw new IllegalArgumentException("The specified attribute is not of type String: " + attrib); //$NON-NLS-1$ } Object str = null; boolean isDesc; VariabilityElement ve; if ( e instanceof ContentDescription ) { ve = (VariabilityElement) e.eContainer(); if ( ve == null ) { ve = (VariabilityElement)ownerElement; } isDesc = true; } else if ( e instanceof VariabilityElement) { ve = (VariabilityElement)e; isDesc = false; } else { // str = e.eGet(attrib); str = TypeDefUtil.getInstance().eGet(e, attrib); return (str==null) ? "" : str.toString(); //$NON-NLS-1$ } if(attrib == UmaPackage.eINSTANCE.getMethodElement_Guid() || attrib == UmaPackage.eINSTANCE.getNamedElement_Name()) { return (String)e.eGet(attrib); } VariabilityElement base = ve.getVariabilityBasedOnElement(); VariabilityType variabilityType = ve.getVariabilityType(); if( base != null && variabilityType == VariabilityType.LOCAL_CONTRIBUTION) { // for local contribution, append the text to the base Object strBase; if ( isDesc ) { // str = ((DescribableElement)ve).getPresentation().eGet(attrib); str = TypeDefUtil.getInstance().eGet(((DescribableElement)ve).getPresentation(), attrib); strBase = calcAttributeFeatureValue( ((DescribableElement)base).getPresentation(), base, attrib, config); } else { str = ve.eGet(attrib); strBase = calcAttributeFeatureValue(base, null, attrib, config); } if ( strBase != null && strBase.toString().length() > 0 ) { if ( str != null && str.toString().length() > 0 ) { str = strBase + ATTRIBUTE_VALUE_SEPERATOR + str; } else { str = strBase; } } } else { str = calcAttributeFeatureValue(e, ve, attrib, config); } return (str==null) ? "" : str.toString(); //$NON-NLS-1$ // List values = new ArrayList(); // VariabilityElement base; // VariabilityType variabilityType; // boolean concat = attrib != UmaPackage.eINSTANCE.getMethodElement_PresentationName(); // while(true) { // base = ve.getVariabilityBasedOnElement(); // if(base == null) { // Object str; // if ( isDesc ) { // str = ((DescribableElement)ve).getPresentation().eGet(attrib); // } else { // str = ve.eGet(attrib); // } // if(str == null || str.toString().length() == 0) { // if(values.isEmpty()) { // values.add(str); // } // } // else { // values.add(0, str); // } // break; // } // else if(base instanceof Activity) { // Object str; // if ( isDesc ) { // str = ((DescribableElement)ve).getPresentation().eGet(attrib); // } else { // str = ve.eGet(attrib); // } // // variabilityType = ve.getVariabilityType(); // if(variabilityType == VariabilityType.EXTENDS_LITERAL) { // if(str == null || str.toString().length() == 0) { // // use the value of the base // // // ve = base; // } // else { // values.add(0, str); // break; // } // } // else if(variabilityType == VariabilityType.LOCAL_CONTRIBUTION_LITERAL) { // if(str != null && str.toString().length() > 0) { // // add to the list // // // values.add(0, str); // if(!concat) { // break; // } // } // // go to the base // ve = base; // } // else if(variabilityType == VariabilityType.LOCAL_REPLACEMENT_LITERAL) { // values.add(0, str); // break; // } // //TODO: handle CONTRIBUTES AND REPLACES // } // } // // if ( values.size() == 0 ) { // return ""; //$NON-NLS-1$ // } // else if ( values.size() ==1 ) { // return (String)values.get(0); // } // else { // StringBuffer buffer = new StringBuffer(); // for (Iterator it = values.iterator(); it.hasNext(); ) { // if ( buffer.length() > 0 ) { // buffer.append(ATTRIBUTE_VALUE_SEPERATOR); // } // buffer.append(it.next()); // } // return buffer.toString(); // } } /** * get all processes in the configuration * * @param config * @return List */ public static List getAllProcesses(MethodConfiguration config) { List processes = new ArrayList(); List plugins = config.getMethodPluginSelection(); for (Iterator it = plugins.iterator(); it.hasNext(); ) { List items = TngUtil.getAllProcesses((MethodPlugin)it.next()); for ( Iterator itp = items.iterator(); itp.hasNext(); ) { org.eclipse.epf.uma.Process p = (org.eclipse.epf.uma.Process)itp.next(); if ( canShow(p, config) && !processes.contains(p) ) { processes.add(p); } } } return processes; } /** * get all processes in the plugin and the configuration * * @param plugin * @param config * @return List */ public static List getAllProcesses(MethodPlugin plugin, MethodConfiguration config) { List processes = new ArrayList(); List items = TngUtil.getAllProcesses(plugin); for ( Iterator itp = items.iterator(); itp.hasNext(); ) { org.eclipse.epf.uma.Process p = (org.eclipse.epf.uma.Process)itp.next(); if ( canShow(p, config) && !processes.contains(p) ) { processes.add(p); } } return processes; } /** * get all delivery processes in the plugin and configuration * @param plugin * @param config * @return List */ public static List getAllDeliveryProcesses(MethodPlugin plugin, MethodConfiguration config) { List processes = new ArrayList(); List items = TngUtil.getAllProcesses(plugin); for ( Iterator itp = items.iterator(); itp.hasNext(); ) { org.eclipse.epf.uma.Process p = (org.eclipse.epf.uma.Process)itp.next(); if ( p instanceof DeliveryProcess ) { if ( canShow(p, config) && !processes.contains(p) ) { processes.add(p); } } } return processes; } /** * get all CapabilityPatterns in the plugin and configuration * * @param plugin * @param config * @return List */ public static List getAllCapabilityPatterns(MethodPlugin plugin, MethodConfiguration config) { List processes = new ArrayList(); List items = TngUtil.getAllProcesses(plugin); for ( Iterator itp = items.iterator(); itp.hasNext(); ) { org.eclipse.epf.uma.Process p = (org.eclipse.epf.uma.Process)itp.next(); if ( p instanceof CapabilityPattern ) { if ( canShow(p, config) && !processes.contains(p) ) { processes.add(p); } } } return processes; } /** * calculate the work products modified by the specified role, in the configuration * * @param element Role * @param ownerElement MethodElement the owner to accept the calculated value * @param realizer * @return List list of work products being modified by the role */ public static List calcModifiedWorkProducts(Role element, MethodElement ownerElement, ElementRealizer realizer) { List v = new ArrayList(); OppositeFeature ofeature = AssociationHelper.Role_Primary_Tasks; ToManyOppositeFeatureValue fv2 = new ToManyOppositeFeatureValue(element, ofeature, realizer); calculateOppositeFeature(element, ofeature, realizer, fv2); if ( fv2.size() > 0 ) { List v2 = (List)fv2.getValue(); EStructuralFeature feature = UmaPackage.eINSTANCE.getTask_Output(); Set set = new LinkedHashSet(); for (Iterator it = v2.iterator(); it.hasNext(); ) { MethodElement e = (MethodElement)it.next(); ToManyFeatureValue fv = new ToManyFeatureValue(element, ownerElement, feature, realizer); // This is wrong: fv.getValue() may return a copy instead of the reference of the internal value field! // ((List)).addAll(v); calculateFeature(e, ownerElement, feature, realizer.getConfiguration(), fv, realizer); // v = (List)fv.getValue(); List list = (List)fv.getValue(); if (list != null && !list.isEmpty()) { set.addAll(list); } } if (! set.isEmpty()) { v.addAll(set); } } return v; } /** * calculate the work product descriptors modified by the specified role descriptor, in the configuration * * @param element RoleDescriptor * @param ownerElement MethodElement the owner to accept the calculated value * @param realizer * @return List list of work product descriptors being modified by the role descriptor * @deprecated use the RoleDescriptorLayout to calculate the feature value */ public static List calcModifiedWorkProductDescriptors(RoleDescriptor element, MethodElement ownerElement, ElementRealizer realizer) { List v = new ArrayList(); OppositeFeature ofeature = AssociationHelper.RoleDescriptor_PrimaryTaskDescriptors; ToManyOppositeFeatureValue fv2 = new ToManyOppositeFeatureValue(element, ofeature, realizer); calculateOppositeFeature(element, ofeature, realizer, fv2); if ( fv2.size() > 0 ) { List v2 = (List)fv2.getValue(); EStructuralFeature feature = UmaPackage.eINSTANCE.getTaskDescriptor_Output(); for (Iterator it = v2.iterator(); it.hasNext(); ) { MethodElement e = (MethodElement)it.next(); ToManyFeatureValue fv = new ToManyFeatureValue(element, ownerElement, feature, realizer); ((List)fv.getValue()).addAll(v); calculateFeature(e, ownerElement, feature, realizer.getConfiguration(), fv, realizer); v = (List)fv.getValue(); } } return v; } /** * calculate the roles that modifies the specified work product in the configuration * @param element WorkProduct * @param realizer * @return List the roles */ public static List calcModifyRoles(WorkProduct element, ElementRealizer realizer) { List tasks = ConfigurationHelper.calc0nFeatureValue( element, AssociationHelper.WorkProduct_OutputFrom_Tasks, realizer); List modifyRoles = new ArrayList(); for (Iterator it = tasks.iterator(); it.hasNext(); ) { Task t = (Task)it.next(); List<Role> rList = (List<Role>)ConfigurationHelper.calc0nFeatureValue( t, UmaPackage.eINSTANCE.getTask_PerformedBy(), realizer); for (Role r: rList) { if ( (r != null) && !modifyRoles.contains(r) ) { modifyRoles.add(r); } } } return modifyRoles; } /** * calculate the role descriptors that modifies the specified work product descriptor in the configuration * @param element WorkProductDescriptor * @param realizer * @return List the role descriptors * @deprecated use the WorkProductDescriptorlayout to calculate the feature value */ public static List calcModifyRoleDescriptors(WorkProductDescriptor element, ElementRealizer realizer) { List taskDescriptors = ConfigurationHelper.calc0nFeatureValue( element, AssociationHelper.WorkProductDescriptor_OutputFrom_TaskDescriptors, realizer); List modifyRoles = new ArrayList(); for (Iterator it = taskDescriptors.iterator(); it.hasNext(); ) { TaskDescriptor t = (TaskDescriptor)it.next(); RoleDescriptor r = (RoleDescriptor)ConfigurationHelper.calc01FeatureValue( t, UmaPackage.eINSTANCE.getTaskDescriptor_PerformedPrimarilyBy(), realizer); if ( (r != null) && !modifyRoles.contains(r) ) { modifyRoles.add(r); } } return modifyRoles; } /** * check if the activity is a contributor * or contains any sub-activities that are contributors * @param element Activity * @return boolean */ public static boolean hasContributor(Activity element) { if ( isContributor(element)) { return true; } for ( Iterator it = element.getBreakdownElements().iterator(); it.hasNext(); ) { Object o = it.next(); if ( !(o instanceof Activity) ) { continue; } if ( hasContributor( (Activity)o ) ) { return true; } } return false; } /** * get the base processes for an {@link Activity} in the Configuration * @param element * @param config * @return List */ public static List getBaseProcesses(Activity element, MethodConfiguration config) { List value = new ArrayList(); getBaseProcesses(element, config, value); return value; } /** * get all base processes for an activity in the configuration * @param element * @param config * @param value List the bases processes */ public static void getBaseProcesses(Activity element, MethodConfiguration config, List value) { // get it's own base if ( ConfigurationHelper.isExtender(element) ) { Activity base = (Activity)element.getVariabilityBasedOnElement(); if ( base != null && !value.contains(base) && (base instanceof org.eclipse.epf.uma.Process) ) { if ( canShow(base, config) ) { value.add(base); } getBaseProcesses(base, config, value); } } // if the sub-activities have base, process it for ( Iterator it = element.getBreakdownElements().iterator(); it.hasNext(); ) { Object o = it.next(); if ( o instanceof Activity ) { getBaseProcesses((Activity)o, config, value); } } } public static URI getInheritingUri(DescribableElement obj, URI uri, VariabilityElement[] uriInheritingBases, MethodConfiguration config, int uriType) { VariabilityElement ve = (VariabilityElement) obj; VariabilityElement base = ve.getVariabilityBasedOnElement(); if (base != null && (ve.getVariabilityType() == VariabilityType.EXTENDS || ve .getVariabilityType() == VariabilityType.EXTENDS_REPLACES)) { base = (VariabilityElement) ConfigurationHelper.getCalculatedElement(base, config); if (base != null) { if (uriType == 0) { uri = ((DescribableElement) base).getNodeicon(); } else if (uriType == 1) { uri = ((DescribableElement) base).getShapeicon(); } if (uri != null) { uriInheritingBases[0] = base; } } } return uri; } }