blob: 9fcc01fb97c9b9d8176552cae6af138270f692c8 [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.Collection;
import java.util.HashMap;
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 org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.ContentCategory;
import org.eclipse.epf.uma.CustomCategory;
import org.eclipse.epf.uma.Discipline;
import org.eclipse.epf.uma.DisciplineGrouping;
import org.eclipse.epf.uma.Domain;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodLibrary;
import org.eclipse.epf.uma.MethodPackage;
import org.eclipse.epf.uma.MethodPlugin;
import org.eclipse.epf.uma.ProcessComponent;
import org.eclipse.epf.uma.ProcessPackage;
import org.eclipse.epf.uma.RoleSet;
import org.eclipse.epf.uma.RoleSetGrouping;
import org.eclipse.epf.uma.Tool;
import org.eclipse.epf.uma.WorkProductType;
/**
* Class managing configuration data calculation and cache
*
* @author Weiping Lu - Mar 20, 2007
* @since 1.2
*/
public class ConfigurationData {
public static boolean active = false; //temp flag to be removed
private MethodConfiguration config;
private Map<String, MethodElementData> substractedElemMap = new HashMap<String, MethodElementData>();
private Map<String, MethodElementData> addedElemMap = new HashMap<String, MethodElementData>();;
private Map<String, ContentCategoryData> substractedCcMap = new HashMap<String, ContentCategoryData>();
private Map<String, ContentCategoryData> addedCcMap = new HashMap<String, ContentCategoryData>();
private boolean needUpdateConfigChange = true;
private Set<ContentCategory> changedContentCategorySet = new HashSet<ContentCategory>();
public ConfigurationData(MethodConfiguration config) {
this.config = config;
Adapter configListener = new AdapterImpl() {
public void notifyChanged(Notification msg) {
int type = msg.getEventType();
if ( type == Notification.ADD
|| type == Notification.ADD_MANY
|| type == Notification.REMOVE
|| type == Notification.REMOVE_MANY) {
needUpdateConfigChange = true;
changedContentCategorySet = null;
}
}
};
config.eAdapters().add(configListener);
}
private void updateConfigChange() {
if (! needUpdateConfigChange) {
return;
}
updateCcMap(substractedCcMap, collectAll(config.getSubtractedCategory()), substractedElemMap);
updateCcMap(addedCcMap, collectAll(config.getAddedCategory()), addedElemMap);
needUpdateConfigChange = false;
}
private Collection<ContentCategory> collectAll(Collection<ContentCategory> ccList) {
if (ccList == null || ccList.isEmpty()) {
return null;
}
Set<ContentCategory> all = new LinkedHashSet<ContentCategory>();
collectAll(ccList, all);
return all;
}
private void collectAll(Collection<ContentCategory> ccList, Set<ContentCategory> all) {
if (ccList == null || ccList.isEmpty()) {
return;
}
for (Iterator<ContentCategory> it = ccList.iterator(); it.hasNext();) {
ContentCategory cc = it.next();
if (! all.contains(cc)) {
all.add(cc);
collectAll(getChildCC(cc), all);
}
}
}
private Collection<ContentCategory> getChildCC(ContentCategory cc) {
if (cc instanceof CustomCategory) {
return ((CustomCategory) cc).getSubCategories();
}
if (cc instanceof Discipline) {
return ((Discipline) cc).getSubdiscipline();
}
if (cc instanceof DisciplineGrouping) {
return ((DisciplineGrouping) cc).getDisciplines();
}
if (cc instanceof Domain) {
return ((Domain) cc).getSubdomains();
}
if (cc instanceof RoleSet) {
return ((RoleSet) cc).getRoles();
}
if (cc instanceof RoleSetGrouping) {
return ((RoleSetGrouping) cc).getRoleSets();
}
if (cc instanceof Tool) {
return ((Tool) cc).getToolMentors();
}
if (cc instanceof WorkProductType) {
return ((WorkProductType) cc).getWorkProducts();
}
return null;
}
private void updateCcMap(Map<String, ContentCategoryData> map, Collection<ContentCategory> ccList,
Map<String, MethodElementData> ccDataOwner) {
if (ccList == null || ccList.isEmpty()) {
return;
}
Map<String, ContentCategoryData> newMap = new HashMap<String, ContentCategoryData>();
boolean changed = false;
for (Iterator<ContentCategory> it = ccList.iterator(); it.hasNext();) {
ContentCategory cc = it.next();
ContentCategoryData ccData = map == null ? null : map.get(cc
.getGuid());
if (ccData == null) {
ccData = new ContentCategoryData(cc, ccDataOwner);
changed = true;
}
newMap.put(cc.getGuid(), ccData);
}
for (Iterator<Map.Entry<String, ContentCategoryData>> it = map
.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, ContentCategoryData> entry = it.next();
String guid = entry.getKey();
ContentCategoryData ccData = entry.getValue();
if (!newMap.containsKey(guid)) {
changed = true;
incOrDecElemMap(ccDataOwner, getElements(ccData.getContentCategory()), false);
}
}
if (changed) {
map = newMap;
}
}
private void updateCcChanges() {
if (changedContentCategorySet == null) {
return;
}
for (Iterator<ContentCategory> it = changedContentCategorySet.iterator(); it.hasNext(); ) {
ContentCategory cc = it.next();
updateCcChange(substractedCcMap, cc);
updateCcChange(addedCcMap, cc);
}
changedContentCategorySet = null;
}
private void updateCcChange(Map<String, ContentCategoryData> map, ContentCategory cc) {
ContentCategoryData ccData = map == null ? null : map.get(cc.getGuid());
if (ccData == null) {
return;
}
assert(ccData.getContentCategory() == cc);
ccData.updateElementMap();
}
//No duplicates in the returned elements
private Collection<MethodElement> getElements(ContentCategory cc) {
//return cc.getCategorizedElements();
return null;
}
private void incOrDecElemMap(Map<String, MethodElementData> map,
Collection<MethodElement> elements, boolean inc) {
for (Iterator<MethodElement> it = elements.iterator(); it.hasNext();) {
incOrDecElemMap(map, it.next(), inc);
}
}
private void incOrDecElemMap(Map<String, MethodElementData> map, MethodElement element,
boolean inc) {
if (map == null) {
return;
}
MethodElementData data = map.get(element.getGuid());
if (data != null) {
assert (element == data.element);
assert (data.refCount > 0);
if (inc) {
data.refCount++;
} else {
data.refCount--;
if (data.refCount == 0) {
map.remove(element.getGuid());
}
}
return;
} else if (!inc) {
return;
}
map.put(element.getGuid(), new MethodElementData(element));
}
public boolean isOwnerSelected(MethodElement element, boolean checkSubtracted) {
if (element == null) {
return false;
}
if (ConfigurationHelper.isDescriptionElement(element)) {
return true;
}
//refresh cache info
updateConfigChange();
updateCcChanges();
// since UMA 1.0.4, configuration can have added categories
// and subtracted categories. The order of filtering is:
// 1. any element in the subtracted categories should be excluded
// 2. any element in the added categories should be included
// 3. any element not in the selected package or plugin should be excluded.
if ( checkSubtracted ) {
if (substractedElemMap.containsKey(element.getGuid())) {
return false;
}
}
if (addedElemMap.containsKey(element.getGuid())) {
return true;
}
// elements beyond configuration scope should be always visible
if ((element instanceof MethodLibrary)
|| (element instanceof MethodConfiguration)) {
return true;
} else if (element instanceof MethodPlugin) {
List plugins = config.getMethodPluginSelection();
return (plugins != null) && plugins.contains(element);
} else {
// if the ownerprocess can't show, can't accept
if (element instanceof Activity) {
Activity base = (Activity) ((Activity) element)
.getVariabilityBasedOnElement();
if (base != null && base != element) {
MethodElement owningProc = TngUtil.getOwningProcess(base);
if ( owningProc != null && owningProc != element
&& !ConfigurationHelper.inConfig(owningProc, config, checkSubtracted)) {
return false;
}
}
}
EObject pkg = LibraryUtil.getSelectable(element);
// accept global package if the plugin is in the configuration
if (pkg instanceof MethodPackage
&& ConfigurationHelper.isGlobalPackage((MethodPackage) pkg)) {
MethodPlugin plugin = LibraryUtil.getMethodPlugin(pkg);
return ConfigurationHelper.inConfig(plugin, config, checkSubtracted);
}
List pkgs = config.getMethodPackageSelection();
if (pkgs == null) {
return false;
}
// per Phong's request, for ProcessPackage, check the
// ProcessComponent parent instead
if (pkg instanceof ProcessPackage) {
while ((pkg != null) && !(pkg instanceof ProcessComponent)
&& !pkgs.contains(pkg)) {
pkg = pkg.eContainer();
}
}
// if package not selected, return false
if ((pkg == null) || !pkgs.contains(pkg)) {
return false;
}
return true;
}
}
private class ContentCategoryData {
private ContentCategory ContentCategory;
private Map<String, MethodElement> elementMap = new HashMap<String, MethodElement>();
private Map<String, MethodElementData> dataMap;
public ContentCategoryData(ContentCategory cc, Map<String, MethodElementData> dataMap) {
ContentCategory = cc;
Adapter ContentCategoryListener = new AdapterImpl() {
public void notifyChanged(Notification msg) {
int type = msg.getEventType();
if ( type == Notification.ADD
|| type == Notification.ADD_MANY
|| type == Notification.REMOVE
|| type == Notification.REMOVE_MANY) {
if (needUpdateConfigChange) {
return;
}
changedContentCategorySet.add(ContentCategory);
}
}
};
ContentCategory.eAdapters().add(ContentCategoryListener);
this.dataMap = dataMap;
updateElementMap();
}
public ContentCategory getContentCategory() {
return ContentCategory;
}
public void updateElementMap() {
Map<String, MethodElement> newMap = new HashMap<String, MethodElement>();
Collection<MethodElement> elementList = getElements(ContentCategory);
boolean changed = false;
for (Iterator<MethodElement> it = elementList.iterator(); it
.hasNext();) {
MethodElement element = it.next();
if (elementMap == null
|| !elementMap.containsKey(element.getGuid())) {
changed = true;
incOrDecElemMap(dataMap, element, true);
}
newMap.put(element.getGuid(), element);
}
for (Iterator<Map.Entry<String, MethodElement>> it = elementMap
.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, MethodElement> entry = it.next();
String guid = entry.getKey();
MethodElement element = entry.getValue();
if (!newMap.containsKey(guid)) {
changed = true;
incOrDecElemMap(dataMap, element, false);
}
}
if (changed) {
elementMap = newMap;
}
}
}
private class MethodElementData {
public MethodElement element;
public int refCount;
public MethodElementData(MethodElement e) {
element = e;
refCount = 1;
}
}
}