blob: 49e4faefb8b7aa2d8211be7367172fa536a2b5b7 [file] [log] [blame]
//------------------------------------------------------------------------------
// 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;
}
}