//------------------------------------------------------------------------------
// 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.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.ecore.util.OppositeFeature;
import org.eclipse.epf.uma.util.AssociationHelper;
import org.eclipse.epf.uma.Process;
/**
* realized feature value for a toMany opposite feature
*
* @author Jinhua Xi
* @since 1.0
*
*/
public class ToManyOppositeFeatureValue extends ToManyFeatureValue {
/**
* @see construct a feature value object for to-many opposite feature
*
* @param element
* @param feature
* @param realizer
*/
public ToManyOppositeFeatureValue(MethodElement element, OppositeFeature feature, ElementRealizer realizer) {
super(element, null, feature, realizer);
}
/**
* @see org.eclipse.epf.library.configuration.ToManyFeatureValue#add(VariabilityElement, Object)
*/
public void add(VariabilityElement owner, Object value) {
// work around for opposite feature value that still return a single value instead of a list
if ( value instanceof MethodElement ) {
ArrayList v = new ArrayList();
v.add(value);
value = v;
}
if ( !(value instanceof List) ) {
return;
}
OppositeFeature of = (OppositeFeature)feature;
EStructuralFeature f = of.getTargetFeature();
for (Iterator it = ((List) value).iterator(); it.hasNext();) {
MethodElement e = (MethodElement) it.next();
//A replaced process should not be shown as a process usage
if (of == AssociationHelper.Task_TaskDescriptors && e instanceof TaskDescriptor) {
TaskDescriptor td = (TaskDescriptor) e;
Process proc = ProcessUtil.getProcess(td.getSuperActivities());
MethodElement realized = ConfigurationHelper.getCalculatedElement(proc, getRealizer());
if (realized != proc) {
continue;
}
}
// Replace does not completely remove
// outgoing associations
// if the opposite feature value has replacer in the
// configuration
// it's outgoing associations (i.e., this element) will be
// replaced by the replacing element
// as a result, the opposite feature value should drop the
// replaced element
//
// for example, R1 -> responsible for A1, R2 responsible for
// A2
// if R2 replaces R1, then R2 still responsible for A2
// but A1 does not have a responsible role (not R2)
// so for A1's responsible role opposite feature,
// the value R1 should be dropped instead of realize to R2
// Jinhua Xi, 10/27/2005
// check the replacer is not enough. If the base element is replaced,
// all the contributors to the base should also be considered as replaced.
// so realize the element, see if it is a replacer
// Bug 199686 - Replacing roles does not update responsible work product's pages
VariabilityElement replacer = null;
if ( e instanceof VariabilityElement ) {
//replacer = ConfigurationHelper.getReplacer((VariabilityElement) e, realizer.getConfiguration());
replacer = (VariabilityElement)ConfigurationHelper.getCalculatedElement(e, realizer);
if ( (replacer == e) || !ConfigurationHelper.isReplacer(replacer) ||
ConfigurationHelper.contrubuteChain((VariabilityElement) e, (VariabilityElement)replacer)) {
replacer = null;
}
}
boolean isValueReplaced = (replacer != null);
boolean keep = !isValueReplaced;
if ( isValueReplaced &&
(ConfigurationHelper.isExtendReplacer(replacer)
|| ElementRealizer.isExtendReplaceEnabled()) ) {
// if the value is replaced, but the out going feature is inherited by the replacer
// then we should keep this value, so we need to calculate the feature value
// of the replacer
if ( f.isMany() ) {
List items = ConfigurationHelper.calc0nFeatureValue(replacer, f, realizer);
keep = items.contains(owner);
} else {
MethodElement item = ConfigurationHelper.calc01FeatureValue(replacer, f, realizer);
keep = (item == owner);
}
}
// if the value's feature to this element is to-one,
// then this value's feature value should be the element,
// otherwise drop the value
// for example,
// T1 -> R1 (primary performaer)
// T2 -> R2
// T2 contributes to T1
// since T1 already has R1, so R2 is droped
// so when calculating R2's performing tasks, T1 should not be included
if ( keep ) {
MethodElement ve = ConfigurationHelper.getCalculatedElement(e, realizer);
if ( ve != null ) {
// check if this is a to-one feature, currently only Task->Primary Role and TD -> Primary RD
EStructuralFeature f1 = ConfigurationHelper.get01Feature(of);
if ( f1 != null ) {
MethodElement item = ConfigurationHelper.calc01FeatureValue(ve, f1, realizer);
// if the value element's to-one feature value item is not the current element,
// then the element's opposite feature value should not contain this value.
// say, the value element is a task and the current element is a role,
// then if the task's primary performer (item above) is not this role (the current element),
// then the role's performing tasks (the opposite feature value)
// should not contain this task (the value, ve above)
if ( item != element) {
keep = false;
}
}
}
}
if ( keep ) {
MethodElement ce = ConfigurationHelper.getCalculatedElement(e, realizer);
// calculated element can be null if it can't show
if (ce != null && !values.contains(ce)) {
values.add(ce);
}
}
// if the element e has extenders and the extender's feature is the owner element,
// then we also need to include the extender
processExtenders(e, f);
}
}
private void processExtenders(MethodElement e, EStructuralFeature f) {
if ( !(e instanceof VariabilityElement) ) {
return;
}
VariabilityElement ve = (VariabilityElement)e;
List items = ConfigurationHelper.getExtenders( ve, realizer.getConfiguration());
if ( items.size() > 0 ) {
for (Iterator it = items.iterator(); it.hasNext();) {
MethodElement me = (MethodElement) it.next();
if (ConfigurationHelper.getCalculatedElement(me, realizer) == null) {
continue;
}
boolean keep = false;
if ( f.isMany() ) {
List vx = ConfigurationHelper.calc0nFeatureValue(me, f, realizer);
// if the value contains the owner element, then include it
keep = (vx != null) && vx.contains(super.element);
} else {
MethodElement v = ConfigurationHelper.calc01FeatureValue(me, f, realizer);
// if the feature value is the owner element, then this value should be included
keep = (v == super.element);
}
if (keep && !super.values.contains(me) ) {
super.values.add(me);
processExtenders(me, f);
}
}
}
// if the element is a contributor or replacer, also need to check the extenders of the base element
if ( ConfigurationHelper.isContributor(ve) || ConfigurationHelper.isReplacer(ve) ) {
processExtenders(ve.getVariabilityBasedOnElement(), f);
}
}
}