com.aurel.track.admin.customize.category.filter.execute.loadItems.LoadItemLinksUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.aurel.track.admin.customize.category.filter.execute.loadItems.LoadItemLinksUtil.java

Source

/**
 * Genji Scrum Tool and Issue Tracker
 * Copyright (C) 2015 Steinbeis GmbH & Co. KG Task Management Solutions
    
 * <a href="http://www.trackplus.com">Genji Scrum Tool</a>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* $Id:$ */

package com.aurel.track.admin.customize.category.filter.execute.loadItems;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.lang.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.aurel.track.beans.TLinkTypeBean;
import com.aurel.track.beans.TReportLayoutBean;
import com.aurel.track.beans.TWorkItemBean;
import com.aurel.track.beans.TWorkItemLinkBean;
import com.aurel.track.dao.DAOFactory;
import com.aurel.track.dao.WorkItemDAO;
import com.aurel.track.fieldType.runtime.helpers.MergeUtil;
import com.aurel.track.fieldType.runtime.system.text.SystemProjectSpecificIssueNoRT;
import com.aurel.track.item.ItemBL;
import com.aurel.track.item.link.ItemLinkBL;
import com.aurel.track.linkType.ILinkType;
import com.aurel.track.linkType.ILinkType.LINK_DIRECTION;
import com.aurel.track.linkType.ILinkType.PARENT_CHILD_EXPRESSION;
import com.aurel.track.linkType.LinkTypeBL;
import com.aurel.track.linkType.MsProjectLinkType;
import com.aurel.track.plugin.PluginManager;
import com.aurel.track.prop.ApplicationBean;
import com.aurel.track.report.execute.ReportBean;
import com.aurel.track.report.execute.ReportBeanLink;
import com.aurel.track.util.GeneralUtils;

public class LoadItemLinksUtil {
    private static final Logger LOGGER = LogManager.getLogger(LoadItemLinksUtil.class);
    private static WorkItemDAO workItemDAO = DAOFactory.getFactory().getWorkItemDAO();

    private LoadItemLinksUtil() {
    }

    /**
     * Add the linked items to reportbeans
     * set also the show value for linked items
     * @param reportBeansList
     * @param personID
     * @param locale
     * @return
     */
    public static List<ReportBean> addAllLinkedWorkItemsToReportBeans(List<ReportBean> reportBeansList,
            List<TWorkItemLinkBean> itemLinkBeans, Integer personID, Locale locale) {
        if (reportBeansList != null) {
            boolean useProjectSpecificID = false;
            ApplicationBean appBean = ApplicationBean.getInstance();
            if (appBean.getSiteBean().getProjectSpecificIDsOn() != null) {
                useProjectSpecificID = appBean.getSiteBean().getProjectSpecificIDsOn().booleanValue();
            }
            List<TWorkItemBean> itemBeanList = new LinkedList<TWorkItemBean>();
            if (reportBeansList != null) {
                for (ReportBean reportBean : reportBeansList) {
                    TWorkItemBean workItemBean = reportBean.getWorkItemBean();
                    itemBeanList.add(workItemBean);
                }
            }
            Map<Integer, SortedSet<ReportBeanLink>> ganntMSProjectReportBeanLinksMap = new HashMap<Integer, SortedSet<ReportBeanLink>>();
            Map<Integer, SortedSet<ReportBeanLink>> allLinkedWorkItemsMap = getAllLinkedWorkItems(itemBeanList,
                    itemLinkBeans, personID, locale, ganntMSProjectReportBeanLinksMap);
            for (ReportBean reportBean : reportBeansList) {
                TWorkItemBean workItemBean = reportBean.getWorkItemBean();
                Integer workItemID = workItemBean.getObjectID();
                SortedSet<ReportBeanLink> reportBeanLinksSet = allLinkedWorkItemsMap.get(workItemID);
                if (reportBeanLinksSet != null) {
                    reportBean.setReportBeanLinksSet(reportBeanLinksSet);
                    //set also the show value
                    StringBuilder stringBuilder = new StringBuilder();
                    for (Iterator<ReportBeanLink> iterator = reportBeanLinksSet.iterator(); iterator.hasNext();) {
                        ReportBeanLink reportBeanLink = iterator.next();
                        String showLink = null;
                        if (useProjectSpecificID) {
                            showLink = reportBeanLink.getProjectSpecificIssueNo();
                        } else {
                            showLink = reportBeanLink.getWorkItemID().toString();
                        }
                        stringBuilder.append(showLink);
                        if (iterator.hasNext()) {
                            stringBuilder.append(" | ");
                        }
                    }
                    Map<Integer, String> showValuesMap = reportBean.getShowValuesMap();
                    if (showValuesMap != null) {
                        showValuesMap.put(TReportLayoutBean.PSEUDO_COLUMNS.LINKED_ITEMS, stringBuilder.toString());
                    }
                }
                SortedSet<ReportBeanLink> ganntMSProjectReportBeanLinksSet = ganntMSProjectReportBeanLinksMap
                        .get(workItemID);
                if (ganntMSProjectReportBeanLinksSet != null) {
                    reportBean.setGanntMSProjectReportBeanLinksSet(ganntMSProjectReportBeanLinksSet);
                }
            }
        }
        return reportBeansList;
    }

    /**
     * Gets all linked workItems
     * @param itemBeanList
     * @param itemLinkBeans
     * @param personID
     * @param locale
     * @param ganntMSProjectReportBeanLinksMap out parameter for "reversed" (gantt compatible MS Project links)
     * @return
     */
    public static Map<Integer, SortedSet<ReportBeanLink>> getAllLinkedWorkItems(List<TWorkItemBean> itemBeanList,
            List<TWorkItemLinkBean> itemLinkBeans, Integer personID, Locale locale,
            Map<Integer, SortedSet<ReportBeanLink>> ganntMSProjectReportBeanLinksMap) {
        Map<Integer, SortedSet<ReportBeanLink>> allLinkedWorkItems = new HashMap<Integer, SortedSet<ReportBeanLink>>();
        Set<Integer> baseWorkItemIDsSet = new HashSet<Integer>();
        Map<Integer, TWorkItemBean> itemBeanMap = new HashMap<Integer, TWorkItemBean>();
        if (itemBeanList != null) {
            for (TWorkItemBean workItemBean : itemBeanList) {
                Integer workItemID = workItemBean.getObjectID();
                baseWorkItemIDsSet.add(workItemID);
                itemBeanMap.put(workItemID, workItemBean);
            }
        }
        if (itemLinkBeans == null) {
            return allLinkedWorkItems;
        }
        Map<Integer, ILinkType> linkTypeIDToLinkTypeMap = LinkTypeBL.getLinkTypeIDToLinkTypeMap();
        //if project specificID is active gather the linked workItems not included in the reportBeanList
        Map<Integer, TWorkItemBean> linkedWorkItemsMap = new HashMap<Integer, TWorkItemBean>();
        Set<Integer> links = new HashSet<Integer>();
        boolean projectSpecificIDsActive = ApplicationBean.getInstance().getSiteBean().getProjectSpecificIDsOn();
        for (TWorkItemLinkBean workItemLinkBean : itemLinkBeans) {
            Integer linkPred = workItemLinkBean.getLinkPred();
            Integer linkSucc = workItemLinkBean.getLinkSucc();
            if (linkPred != null && !baseWorkItemIDsSet.contains(linkPred)) {
                links.add(linkPred);
            }
            if (linkSucc != null && !baseWorkItemIDsSet.contains(linkSucc)) {
                links.add(linkSucc);
            }
        }
        if (!links.isEmpty()) {
            List<TWorkItemBean> linkedWorkItemBeans = LoadItemIDListItems.getWorkItemBeansByWorkItemIDs(
                    GeneralUtils.createIntArrFromIntegerCollection(links), personID, false, false, false);
            for (TWorkItemBean workItemBean : linkedWorkItemBeans) {
                linkedWorkItemsMap.put(workItemBean.getObjectID(), workItemBean);
            }
        }
        Map<String, String> linkTypeNames = LinkTypeBL.getLinkTypeNamesMap(locale);
        Map<Integer, TLinkTypeBean> allLinkTypesMap = GeneralUtils.createMapFromList(LinkTypeBL.loadAll());
        List<Integer> msProjectLinkTypes = null;
        //gather the MSProject link types if Gantt MSProject links are needed
        if (ganntMSProjectReportBeanLinksMap != null) {
            MsProjectLinkType msProjectLinkType = MsProjectLinkType.getInstance();
            msProjectLinkTypes = LinkTypeBL.getLinkTypesByPluginClass(msProjectLinkType);
        }
        for (TWorkItemLinkBean workItemLinkBean : itemLinkBeans) {
            Integer linkID = workItemLinkBean.getObjectID();
            Integer linkTypeID = workItemLinkBean.getLinkType();
            Integer linkDirection = workItemLinkBean.getLinkDirection();
            Integer linkPred = workItemLinkBean.getLinkPred();
            Integer linkSucc = workItemLinkBean.getLinkSucc();
            if (linkSucc == null) {
                //link to a non-workItem
                continue;
            }
            TLinkTypeBean linkTypeBean = allLinkTypesMap.get(linkTypeID);
            if (linkTypeBean != null) {
                SortedSet<ReportBeanLink> allLinksForWorkItem;
                Integer linkTypeDirection = linkTypeBean.getLinkDirection();
                ILinkType linkType = null;
                switch (linkTypeDirection) {
                case LINK_DIRECTION.UNIDIRECTIONAL_OUTWARD:
                    allLinksForWorkItem = allLinkedWorkItems.get(linkPred);
                    if (allLinksForWorkItem == null) {
                        allLinksForWorkItem = new TreeSet<ReportBeanLink>();
                        allLinkedWorkItems.put(linkPred, allLinksForWorkItem);
                    }
                    TWorkItemBean linkedItemBeanOutward = getLinkedReportBean(itemBeanMap, linkSucc);
                    String outwardLinkTitle = getLinkedItemTitle(linkedItemBeanOutward, linkedWorkItemsMap,
                            linkSucc);
                    ReportBeanLink reportBeanLinkOutward = new ReportBeanLink(linkID, linkSucc, outwardLinkTitle,
                            linkedItemBeanOutward != null, linkTypeID, linkDirection,
                            linkTypeNames.get(MergeUtil.mergeKey(linkTypeID, linkDirection)));
                    if (projectSpecificIDsActive && linkSucc != null) {
                        reportBeanLinkOutward.setProjectSpecificIssueNo(
                                getProjectSpecificIssueNo(linkedItemBeanOutward, linkedWorkItemsMap, linkSucc));
                    }
                    linkType = linkTypeIDToLinkTypeMap.get(linkTypeID);
                    if (linkType != null) {
                        reportBeanLinkOutward
                                .setLinkSpecificData(linkType.getItemLinkSpecificData(workItemLinkBean));
                    }
                    allLinksForWorkItem.add(reportBeanLinkOutward);
                    break;
                case LINK_DIRECTION.UNIDIRECTIONAL_INWARD:
                    allLinksForWorkItem = allLinkedWorkItems.get(linkSucc);
                    if (allLinksForWorkItem == null) {
                        allLinksForWorkItem = new TreeSet<ReportBeanLink>();
                        allLinkedWorkItems.put(linkSucc, allLinksForWorkItem);
                    }
                    TWorkItemBean linkedItemBeanInward = getLinkedReportBean(itemBeanMap, linkPred);
                    String inwardLinkTitle = getLinkedItemTitle(linkedItemBeanInward, linkedWorkItemsMap, linkPred);
                    ReportBeanLink reportBeanLinkInward = new ReportBeanLink(linkID, linkPred, inwardLinkTitle,
                            linkedItemBeanInward != null, linkTypeID, linkDirection,
                            linkTypeNames.get(MergeUtil.mergeKey(linkTypeID, linkDirection)));
                    if (projectSpecificIDsActive && linkPred != null) {
                        reportBeanLinkInward.setProjectSpecificIssueNo(
                                getProjectSpecificIssueNo(linkedItemBeanInward, linkedWorkItemsMap, linkPred));
                    }
                    linkType = linkTypeIDToLinkTypeMap.get(linkTypeID);
                    if (linkType != null) {
                        reportBeanLinkInward
                                .setLinkSpecificData(linkType.getItemLinkSpecificData(workItemLinkBean));
                    }
                    allLinksForWorkItem.add(reportBeanLinkInward);
                    if (ganntMSProjectReportBeanLinksMap != null && msProjectLinkTypes != null
                            && msProjectLinkTypes.contains(linkTypeID)) {
                        //for Gantt chart the predecessors should contain the successors: same as it would be UNIDIRECTIONAL_OUTWARD, but only for msProject link types
                        SortedSet<ReportBeanLink> ganntMSProjectReportBeanLinkSet = ganntMSProjectReportBeanLinksMap
                                .get(linkPred);
                        if (ganntMSProjectReportBeanLinkSet == null) {
                            ganntMSProjectReportBeanLinkSet = new TreeSet<ReportBeanLink>();
                            ganntMSProjectReportBeanLinksMap.put(linkPred, ganntMSProjectReportBeanLinkSet);
                        }
                        reportBeanLinkInward = new ReportBeanLink(linkID, linkSucc, inwardLinkTitle,
                                linkedItemBeanInward != null, linkTypeID, linkDirection,
                                linkTypeNames.get(MergeUtil.mergeKey(linkTypeID, linkDirection)));
                        //now only the MsProject links for the gantt chart need this specific data
                        reportBeanLinkInward.setLinkSpecificData(
                                MsProjectLinkType.getInstance().getItemLinkSpecificData(workItemLinkBean));
                        if (projectSpecificIDsActive && linkPred != null) {
                            reportBeanLinkInward.setProjectSpecificIssueNo(
                                    getProjectSpecificIssueNo(linkedItemBeanInward, linkedWorkItemsMap, linkSucc));
                        }
                        ganntMSProjectReportBeanLinkSet.add(reportBeanLinkInward);
                    }
                    break;
                case LINK_DIRECTION.BIDIRECTIONAL:
                    allLinksForWorkItem = allLinkedWorkItems.get(linkPred);
                    if (allLinksForWorkItem == null) {
                        allLinksForWorkItem = new TreeSet<ReportBeanLink>();
                        allLinkedWorkItems.put(linkPred, allLinksForWorkItem);
                    }
                    TWorkItemBean succLinkedItemBean = getLinkedReportBean(itemBeanMap, linkSucc);
                    String succLinkTitle = getLinkedItemTitle(succLinkedItemBean, linkedWorkItemsMap, linkSucc);
                    ReportBeanLink reportBeanLinkSucc = new ReportBeanLink(linkID, linkSucc, succLinkTitle,
                            succLinkedItemBean != null, linkTypeID, linkDirection,
                            linkTypeNames.get(MergeUtil.mergeKey(linkTypeID, linkDirection)));
                    if (projectSpecificIDsActive && linkSucc != null) {
                        reportBeanLinkSucc.setProjectSpecificIssueNo(
                                getProjectSpecificIssueNo(succLinkedItemBean, linkedWorkItemsMap, linkSucc));
                    }
                    linkType = linkTypeIDToLinkTypeMap.get(linkTypeID);
                    if (linkType != null) {
                        reportBeanLinkSucc.setLinkSpecificData(linkType.getItemLinkSpecificData(workItemLinkBean));
                    }
                    allLinksForWorkItem.add(reportBeanLinkSucc);
                    if (linkDirection != null) {
                        int reverseDirection = LinkTypeBL.getReverseDirection(linkDirection.intValue());
                        allLinksForWorkItem = allLinkedWorkItems.get(linkSucc);
                        if (allLinksForWorkItem == null) {
                            allLinksForWorkItem = new TreeSet<ReportBeanLink>();
                            allLinkedWorkItems.put(linkSucc, allLinksForWorkItem);
                        }
                        TWorkItemBean predLinkedItemBean = getLinkedReportBean(itemBeanMap, linkPred);
                        String predLinkTitle = getLinkedItemTitle(predLinkedItemBean, linkedWorkItemsMap, linkPred);
                        ReportBeanLink reportBeanLinkPred = new ReportBeanLink(linkID, linkPred, predLinkTitle,
                                predLinkedItemBean != null, linkTypeID, Integer.valueOf(reverseDirection),
                                linkTypeNames
                                        .get(MergeUtil.mergeKey(linkTypeID, Integer.valueOf(reverseDirection))));
                        if (projectSpecificIDsActive && linkPred != null) {
                            reportBeanLinkPred.setProjectSpecificIssueNo(
                                    getProjectSpecificIssueNo(predLinkedItemBean, linkedWorkItemsMap, linkPred));
                        }
                        if (linkType != null) {
                            reportBeanLinkPred
                                    .setLinkSpecificData(linkType.getItemLinkSpecificData(workItemLinkBean));
                        }
                        allLinksForWorkItem.add(reportBeanLinkPred);
                    }
                    break;
                default:
                    break;
                }
            }
        }
        return allLinkedWorkItems;
    }

    /**
     * Gets the report bean corresponding to the linked item
     * If the linked item is not in the result then it returns null;
     * @param itemBeanMap
     * @param linkedWorkItemID
     * @return
     */
    private static TWorkItemBean getLinkedReportBean(Map<Integer, TWorkItemBean> itemBeanMap,
            Integer linkedWorkItemID) {
        if (itemBeanMap != null) {
            return itemBeanMap.get(linkedWorkItemID);
        }
        return null;
    }

    /**
     * Gets the linked item's title
     * @param baseItemBean might be null
     * @param linkedWorkItemsMap
     * @param linkedWorkItemID
     * @return
     */
    private static String getLinkedItemTitle(TWorkItemBean baseItemBean,
            Map<Integer, TWorkItemBean> linkedWorkItemsMap, Integer linkedWorkItemID) {
        if (baseItemBean != null) {
            return baseItemBean.getSynopsis();
        } else {
            if (linkedWorkItemsMap != null) {
                TWorkItemBean workItemBean = linkedWorkItemsMap.get(linkedWorkItemID);
                if (workItemBean != null) {
                    return workItemBean.getSynopsis();
                }
            }
        }
        return "";
    }

    /**
     * Gets the project specific item number
     * @param reportBeanMap
     * @param linkedWorkItemsMap
     * @param linkedWorkItemID
     * @return
     */
    private static String getProjectSpecificIssueNo(TWorkItemBean baseItemBean,
            Map<Integer, TWorkItemBean> linkedWorkItemsMap, Integer linkedWorkItemID) {
        if (baseItemBean != null) {
            return SystemProjectSpecificIssueNoRT.getShowValue(baseItemBean.getIDNumber(), baseItemBean);
        } else {
            if (linkedWorkItemsMap != null) {
                TWorkItemBean workItemBean = linkedWorkItemsMap.get(linkedWorkItemID);
                if (workItemBean != null) {
                    return SystemProjectSpecificIssueNoRT.getShowValue(workItemBean.getIDNumber(), workItemBean);
                }
            }
        }
        return "";
    }

    /**
     * Get the linked items: either linked though parent or children hierarchy or through plugin links
     * It is very important to remove those linked/parent/child issues which are
     * already contained in the result set to avoid adding them once again
     * @param linkTypeFilterSuperset
     * @param archived
     * @param deleted
     * @param itemTypesList
     * @param baseWorkItemBeanList
     */
    public static int[] getLinkedWorkItemIDs(String linkTypeFilterSuperset, Integer archived, Integer deleted,
            List<Integer> itemTypesList, List<TWorkItemBean> baseWorkItemBeanList) {
        if (linkTypeFilterSuperset == null || "".equals(linkTypeFilterSuperset) || baseWorkItemBeanList == null
                || baseWorkItemBeanList.isEmpty()) {
            return null;
        } else {
            List<Integer> baseWorkItemIDsList = GeneralUtils.createIntegerListFromBeanList(baseWorkItemBeanList);
            int[] baseWorkItemIDsArr = GeneralUtils.createIntArrFromIntegerList(baseWorkItemIDsList);
            Integer[] parts = MergeUtil.getParts(linkTypeFilterSuperset);
            Integer linkType = parts[0];
            Integer direction = parts[1];
            Set<Integer> linkedWorkItemIDsSet = null;
            if (ILinkType.PARENT_CHILD == linkType.intValue()) {
                if (PARENT_CHILD_EXPRESSION.ALL_PARENTS == direction) {
                    linkedWorkItemIDsSet = getParentHierarchy(baseWorkItemBeanList, archived, deleted);
                } else {
                    linkedWorkItemIDsSet = ItemBL.getChildHierarchy(baseWorkItemIDsArr, direction, archived,
                            deleted, itemTypesList);
                }
            } else {
                Map<Integer, SortedSet<Integer>> linkedWorkItemIDsMap = getLinkedWorkItemIDsMap(baseWorkItemIDsList,
                        linkType, direction, archived, deleted);
                linkedWorkItemIDsSet = getFlatItems(linkedWorkItemIDsMap);
            }
            //remove those linked/parent/child issues which are
            //already contained in the result set to avoid adding them once again
            if (linkedWorkItemIDsSet != null) {
                linkedWorkItemIDsSet.removeAll(GeneralUtils.createSetFromIntArr(baseWorkItemIDsArr));
            }
            return GeneralUtils.createIntArrFromSet(linkedWorkItemIDsSet);
        }
    }

    /**
     * Loads all dependent items in allItemIDSet
     * @param baseWorkItemBeans
     * @param archived
     * @param deleted
     * @param allItemIDSet
     */
    public static void loadAllDependentItems(List<TWorkItemBean> baseWorkItemBeans, Integer archived,
            Integer deleted, Set<Integer> allItemIDSet) {
        Set<Integer> linkedItemIDsSet = loadAncestorDescendantAndDirectLinkedItems(baseWorkItemBeans, archived,
                deleted, allItemIDSet);
        int i = 0;
        LOGGER.debug("Number of linked items at level " + i);
        while (linkedItemIDsSet != null && linkedItemIDsSet.size() > 0) {
            List<TWorkItemBean> linkedItemBeans = ItemBL
                    .loadByWorkItemKeys(GeneralUtils.createIntArrFromSet(linkedItemIDsSet));
            i++;
            linkedItemIDsSet = loadAncestorDescendantAndDirectLinkedItems(linkedItemBeans, archived, deleted,
                    allItemIDSet);
            LOGGER.debug("Number of linked items at level " + i);
        }
    }

    /**
     * 
     * @param baseWorkItemBeanList
     * @param archived
     * @param deleted
     * @param allItemIDSet
     * @return
     */
    private static Set<Integer> loadAncestorDescendantAndDirectLinkedItems(List<TWorkItemBean> baseWorkItemBeanList,
            Integer archived, Integer deleted, Set<Integer> allItemIDSet) {
        Set<Integer> originalItemIDSet = GeneralUtils.createIntegerSetFromBeanList(baseWorkItemBeanList);
        LOGGER.debug("Number of items in filter " + originalItemIDSet.size());
        Set<Integer> ancestorWorkItemIDsSet = getParentHierarchy(baseWorkItemBeanList, archived, deleted);
        LOGGER.debug("Number of ascendent items " + ancestorWorkItemIDsSet.size());
        allItemIDSet.addAll(originalItemIDSet);
        allItemIDSet.addAll(ancestorWorkItemIDsSet);
        Set<Integer> descendantItemIDSet = ItemBL.getChildHierarchy(
                GeneralUtils.createIntArrFromIntegerCollection(allItemIDSet), PARENT_CHILD_EXPRESSION.ALL_CHILDREN,
                archived, deleted, null);
        LOGGER.debug("Total number of descendent items " + descendantItemIDSet.size());
        allItemIDSet.addAll(descendantItemIDSet);
        //gather the MSProject link types
        MsProjectLinkType msProjectLinkType = MsProjectLinkType.getInstance();
        List<Integer> msProjectLinkTypes = LinkTypeBL.getLinkTypesByPluginClass(msProjectLinkType);
        //although Msproject link is unidirectional, we have to load also the predecessors in order to avoid moving back the successor items
        Map<Integer, SortedSet<Integer>> linkDependencyMap = ItemLinkBL.loadByWorkItemsAndLinkType(
                GeneralUtils.createIntegerListFromCollection(allItemIDSet), msProjectLinkTypes,
                msProjectLinkType.getPossibleDirection(), true, archived, deleted);
        Set<Integer> linkedItemIDsSet = getFlatItems(linkDependencyMap);
        LOGGER.debug("Number of linked items from hierarchy " + linkedItemIDsSet.size());
        linkedItemIDsSet.removeAll(allItemIDSet);
        LOGGER.debug("Number of extended linked items " + linkedItemIDsSet.size());
        allItemIDSet.addAll(linkedItemIDsSet);
        return linkedItemIDsSet;
    }

    public static int[] getMsProjectLinkedWorkItemIDs(Integer archived, Integer deleted,
            List<TWorkItemBean> baseWorkItemBeanList) {
        List<TLinkTypeBean> linkTypeBeans = LinkTypeBL.loadAll();
        Integer linkTypeID = null;
        for (Iterator<TLinkTypeBean> iterator = linkTypeBeans.iterator(); iterator.hasNext();) {
            TLinkTypeBean linkTypeBean = iterator.next();
            linkTypeID = linkTypeBean.getObjectID();
            String linkTypePluginClass = LinkTypeBL.getLinkTypePluginString(linkTypeID);
            ILinkType linkType = (ILinkType) PluginManager.getInstance()
                    .getPluginClass(PluginManager.LINKTYPE_ELEMENT, linkTypePluginClass);
            if (linkType.isGanttSpecific()) {
                break;
            }
        }
        String ganttLinkType = "";
        if (linkTypeID != null) {
            ganttLinkType = linkTypeID.toString() + "_" + "2";
        }
        if (!"".equals(ganttLinkType)) {
            return getLinkedWorkItemIDs(ganttLinkType, archived, deleted, null, baseWorkItemBeanList);
        }
        return ArrayUtils.EMPTY_INT_ARRAY;
    }

    /**
     * Get all ascendents which are not included in the original query result
     * @param baseWorkItemBeans
     * @return
     */
    private static Set<Integer> getParentHierarchy(List<TWorkItemBean> baseWorkItemBeans, Integer archived,
            Integer deleted) {
        Set<Integer> allAscendentIDsSet = new HashSet<Integer>();
        if (baseWorkItemBeans != null) {
            //to avoid infinite cycles by inconsistent data
            Set<Integer> toRemoveSet = GeneralUtils.createIntegerSetFromBeanList(baseWorkItemBeans);
            List<TWorkItemBean> workItemBeans = baseWorkItemBeans;
            Set<Integer> notIncludedParentIDs;
            int i = 0;
            do {
                notIncludedParentIDs = new HashSet<Integer>();
                if (workItemBeans != null) {
                    for (TWorkItemBean workItemBean : workItemBeans) {
                        Integer parentID = workItemBean.getSuperiorworkitem();
                        if (parentID != null && !toRemoveSet.contains(parentID)) {
                            notIncludedParentIDs.add(parentID);
                        }
                    }
                }
                i++;
                LOGGER.debug(notIncludedParentIDs.size() + " parents found at " + i + ". level");
                //gather the not yet present parents to the remove set to avoid infinite cycles by inconsistent data
                workItemBeans = null;
                if (!notIncludedParentIDs.isEmpty()) {
                    toRemoveSet.addAll(notIncludedParentIDs);
                    //get the next level of parent workItems
                    workItemBeans = workItemDAO.loadByWorkItemKeys(
                            GeneralUtils.createIntArrFromSet(notIncludedParentIDs), archived, deleted);
                    //retain only the workItems with corresponding archive/delete
                    notIncludedParentIDs.retainAll(GeneralUtils.createIntegerListFromBeanList(workItemBeans));
                    //add the not yet present parents to the list
                    allAscendentIDsSet.addAll(notIncludedParentIDs);
                }
            } while (!notIncludedParentIDs.isEmpty());
        }
        return allAscendentIDsSet;
    }

    /**
     * Gets the linked issues to add
     * @param baseWorkItemIDsList
     * @param linkType
     * @param direction
     * @param archived
     * @param deleted
     * @return
     */
    private static Map<Integer, SortedSet<Integer>> getLinkedWorkItemIDsMap(List<Integer> baseWorkItemIDsList,
            Integer linkType, Integer direction, Integer archived, Integer deleted) {
        if (linkType == null || LinkTypeBL.loadByPrimaryKey(linkType) == null) {
            //the link type is null or is a link type which was deleted previously return an empty array
            //(it can happen because there is no foreign key relationship for the expressions in CLOB values)
            return new HashMap<Integer, SortedSet<Integer>>();
        }
        String linkTypePluginClass = LinkTypeBL.getLinkTypePluginString(linkType);
        ILinkType linkTypeBase = (ILinkType) PluginManager.getInstance()
                .getPluginClass(PluginManager.LINKTYPE_ELEMENT, linkTypePluginClass);
        boolean isBidirectional = LinkTypeBL.isBidirectional(linkType);
        //If link type == Gantt /Ms. project/ we need to obtains predecessors and successors
        if (linkTypeBase.isGanttSpecific()) {
            isBidirectional = true;
        }

        List<Integer> linkTypes = new ArrayList<Integer>();
        if (linkType != null) {
            linkTypes.add(linkType);
        }
        return ItemLinkBL.loadByWorkItemsAndLinkType(baseWorkItemIDsList, linkTypes, direction, isBidirectional,
                archived, deleted);
    }

    /**
     * Get the linked workItemIDs
     * @param linkedWorkItemIDsMap
     * @return
     */
    private static SortedSet<Integer> getFlatItems(Map<Integer, SortedSet<Integer>> linkedWorkItemIDsMap) {
        //get the flat linked items
        SortedSet<Integer> linkedWorkItemIDsSet = new TreeSet<Integer>();
        if (linkedWorkItemIDsMap != null) {
            Iterator<SortedSet<Integer>> iterator = linkedWorkItemIDsMap.values().iterator();
            while (iterator.hasNext()) {
                linkedWorkItemIDsSet.addAll(iterator.next());
            }
        }
        return linkedWorkItemIDsSet;
    }
}