//------------------------------------------------------------------------------ // Copyright (c) 2005, 2007 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.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.epf.library.LibraryPlugin; import org.eclipse.epf.library.edit.IFilter; import org.eclipse.epf.library.edit.PresentationContext; import org.eclipse.epf.library.layout.BrowsingLayoutSettings; import org.eclipse.epf.library.util.LibraryUtil; import org.eclipse.epf.uma.CustomCategory; 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.RoleDescriptor; 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.WorkProductDescriptor; import org.eclipse.epf.uma.util.AssociationHelper; import org.eclipse.epf.uma.util.Scope; /** * Realizes the element based on the configuration and realize options. * * @author Jinhua Xi * @author Weiping Lu * @since 1.0 */ public abstract class ElementRealizer { protected MethodConfiguration config; // note: discard contributor takes higher priority, if set to true, // resolveContributor will be ignored private boolean discardContributor = false; private boolean resolveContributor = true; private boolean resolveReplacer = true; private boolean showSubtracted = false; protected IFilter filter = null; // this is the default setting based on the preference setting // subclass should implement their own method the get the value private static boolean defaultEnableExtendReplace = false; //private static boolean defaultIgnoreBaseToManyAssociations = false; static { String str = LibraryPlugin.getDefault().getString("EnableExtendReplace"); //$NON-NLS-1$ if ( str != null && str.trim().equals("true") ) { //$NON-NLS-1$ defaultEnableExtendReplace = true; } // 171882 - Extends-Replace Variability //defaultIgnoreBaseToManyAssociations = LibraryPreferences.getUseNewExtendsSemantics(); } /** * construct an instance with the give configuration * @param config MethodConfiguration */ public ElementRealizer(MethodConfiguration config) { this(config, true, true); } /** * construct an instance with the given configuration and additional realization options. * * @param config MethodConfiguration * @param resolveContributor boolean if true, contrubutors from feature value list will be resolved. default to false. * @param resolveReplacer boolean if ture, element with a replacer will be resolved to the replacer. default to true. */ public ElementRealizer(MethodConfiguration config, boolean resolveContributor, boolean resolveReplacer) { this.config = config; this.resolveContributor = resolveContributor; this.resolveReplacer = resolveReplacer; } /** * is extend-replace enabled for replacement * * @return boolean */ public static boolean isExtendReplaceEnabled() { return defaultEnableExtendReplace; } /** * get the global setting for the extend semantics * @return */ public static boolean ignoreBaseToManyAssociations() { return BrowsingLayoutSettings.INSTANCE.isUseNewExtendSemantics(); } /** * set the flag. if true, the contributors from a realized feature list will be discarded * * @param discardContributor boolean */ public void setDiscardContributor(boolean discardContributor) { this.discardContributor = discardContributor; } /** * set the flag. if true the contributors will be resolved. * @param resolveContributor boolean */ public void setResolveContributor(boolean resolveContributor) { this.resolveContributor = resolveContributor; } /** * set the flag. if true the element with a replacer will be resolved to the replacer. * * @param resolveReplacer boolean */ public void setResolveReplacer(boolean resolveReplacer) { this.resolveReplacer = resolveReplacer; } public boolean showSubtracted() { return showSubtracted; } public void setShowSubtracted(boolean flag) { this.showSubtracted = flag; } /** * set a filter for this realizer * @param filter IFilter */ public void setFilter(IFilter filter) { this.filter = filter; } /** * get tyhe configuration * @return */ public MethodConfiguration getConfiguration() { return config; } /** * realize the element * @param element MethodElement * @return MethodElement */ public MethodElement realize(MethodElement element) { MethodElement result = realize_(element); if (result == null && element instanceof VariabilityElement) { VariabilityElement ve = (VariabilityElement) element; if (ve.getVariabilityType() == VariabilityType.REPLACES) { if (ve.getVariabilityBasedOnElement() != null) { return realize(ve.getVariabilityBasedOnElement()); } } } return result; } private MethodElement realize_(MethodElement element) { if (getConfiguration() instanceof Scope) { if (element instanceof VariabilityElement) { VariabilityElement ve = (VariabilityElement) element; while(ve.getVariabilityType() == VariabilityType.CONTRIBUTES) { VariabilityElement base = ve.getVariabilityBasedOnElement(); if (base == null) { break; } ve = base; } element = ve; } if (element == null || !inConfig(element)) { return null; } return element; } if (element == null || !inConfig(element)) { return null; } // Work product descriptors that point to work products // outside the configuration are still published // linked element must be in config as well MethodElement linkedElement = null; if (element instanceof TaskDescriptor) { linkedElement = ((TaskDescriptor) element).getTask(); } else if (element instanceof WorkProductDescriptor) { linkedElement = ((WorkProductDescriptor) element).getWorkProduct(); } else if (element instanceof RoleDescriptor) { linkedElement = ((RoleDescriptor) element).getRole(); } if ((linkedElement != null) && !inConfig(linkedElement)) { return null; } // if no configuration is specified, don't calculate if (config == null) { return element; } if (element instanceof VariabilityElement) { VariabilityElement ve = (VariabilityElement) element; VariabilityElement e; // if discardContributor set to true, discard the contributor and // return null if (discardContributor && ConfigurationHelper.isContributor(ve)) { return null; } if (resolveContributor) { // if the element is a contributor, resovle to it's base while (ConfigurationHelper.isContributor(ve)) { e = ve.getVariabilityBasedOnElement(); if (inConfig(e)) { ve = e; } else { // if the base is not in the configuration, it's an // error System.out .println("Configuration closure error: Base element '" + LibraryUtil.getTypeName(ve) + "' not in configuration"); //$NON-NLS-1$ //$NON-NLS-2$ break; } } } if (resolveReplacer) { e = ConfigurationHelper.getReplacer(ve, config); if (e != null) { return e; } } else if (!inConfig(ve)) { return null; } // if the element is a replacer, and the base is a contributor, // need to resolve the element to the base if resolveContributor is true // 152230 - Browsing: Role<-->WP relationship shows inconsistancy e = ve; while ((e != null) && (ConfigurationHelper.isReplacer(e) || ConfigurationHelper.isExtendReplacer(e))) { e = (VariabilityElement) e.getVariabilityBasedOnElement(); if (ConfigurationHelper.isContributor(e)) { return realize(e); } } // can't return here, need to check canShow // return ve; if (canShow(ve)) { return ve; } return null; } if (canShow(element)) { return element; } return null; } /** * realize the list of feature values and returns a new list of values * The new might be a re-sorting of the original list * or some of the values can be filtered out, depending on the detail implementation * Note: the list value passed in might be updated as well. * @param element MethodElement * @param feature EStructuralFeature * @param values List * @return List */ public abstract List realize(MethodElement element, EStructuralFeature feature, List values); /** * * @param element * @return boolean */ public boolean inConfig(MethodElement element) { return ConfigurationHelper.inConfig(element, config, !showSubtracted()); } /** * * @param element * @return boolean */ public boolean canShow(MethodElement element) { return ConfigurationHelper.canShow(element, config, !showSubtracted()); } public void dispose() { this.filter = null; } protected void addExtraFeatureValues(MethodElement element, EStructuralFeature feature, FeatureValue values) { if (!ElementRealizer.toAddExtraFeatureValues(element, feature, values, getConfiguration())) { return; } CustomCategory cc = (CustomCategory) element; Collection<?> result = LibraryUtil.getIncludedElements(cc, getConfiguration()); if (result == null || result.isEmpty()) { return; } ToManyFeatureValue manyValues = values instanceof ToManyFeatureValue ? (ToManyFeatureValue) values : null; List oldValues = manyValues == null ? null : (List) manyValues.getValue(); HashSet<DescribableElement> seenSet = manyValues == null ? new HashSet<DescribableElement>() : new HashSet<DescribableElement>(oldValues); seenSet.add(cc); List ccList = AssociationHelper.getCustomCategories(cc); seenSet.addAll(ccList); List<DescribableElement> list = calculateList(result, seenSet); values.add(cc, list); } public List<DescribableElement> calculateList(Collection<?> result, Set<DescribableElement> seenSet) { Set resultSet = null; List<DescribableElement> list = new ArrayList<DescribableElement>(); for (Iterator<?> iter = result.iterator(); iter.hasNext();) { Object o = iter.next(); if (o instanceof DescribableElement) { DescribableElement contElem0 = (DescribableElement) o; DescribableElement contElem = (DescribableElement) ConfigurationHelper .getCalculatedElement(contElem0, this); if (contElem != null) { if (seenSet.add(contElem)) { boolean toAdd = true; if (contElem0 instanceof VariabilityElement) { VariabilityElement ve = (VariabilityElement) contElem0; VariabilityElement base = ve.getVariabilityBasedOnElement(); if (base != null && ve.getVariabilityType() == VariabilityType.CONTRIBUTES) { if (resultSet == null) { resultSet = new HashSet<Object>(result); } if (! resultSet.contains(contElem)) { toAdd = false; } } } if (toAdd) { list.add(contElem); } } } } } if (list.size() > 1) { Comparator comparator = PresentationContext.INSTANCE.getPresNameComparator(); Collections.<DescribableElement>sort(list, comparator); } return list; } protected boolean slotMatching(FulfillableElement slot, FulfillableElement element) { return true; } protected static boolean toAddExtraFeatureValues(MethodElement element, EStructuralFeature feature, FeatureValue values, MethodConfiguration config) { if (config == null) { return false; } if (!(values instanceof ToManyFeatureValue)) { return false; } if (!(element instanceof CustomCategory)) { return false; } if (feature != UmaPackage.eINSTANCE .getCustomCategory_CategorizedElements()) { return false; } return true; } }