Java tutorial
/** * 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.persist; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Date; 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 com.aurel.track.util.IntegerStringBean; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.apache.torque.Torque; import org.apache.torque.TorqueException; import org.apache.torque.util.Criteria; import org.apache.torque.util.Criteria.Criterion; import org.apache.torque.util.Transaction; import com.aurel.track.admin.customize.category.filter.execute.loadItems.criteria.CriteriaUtil; import com.aurel.track.admin.customize.category.filter.execute.loadItems.criteria.MeetingCriteria; import com.aurel.track.admin.customize.category.filter.execute.loadItems.criteria.ResponsibleCriteria; import com.aurel.track.admin.customize.category.filter.execute.loadItems.criteria.TreeFilterCriteria; import com.aurel.track.admin.customize.category.filter.tree.design.FilterUpperTO; import com.aurel.track.admin.customize.category.filter.tree.design.RACIBean; import com.aurel.track.admin.customize.treeConfig.field.FieldBL; import com.aurel.track.beans.TListTypeBean; import com.aurel.track.beans.TPersonBean; import com.aurel.track.beans.TStateBean; import com.aurel.track.beans.TWorkItemBean; import com.aurel.track.cluster.ClusterMarkChangesBL; import com.aurel.track.dao.WorkItemDAO; import com.aurel.track.dao.torque.SimpleCriteria; import com.aurel.track.errors.ErrorData; import com.aurel.track.exchange.excel.ExcelImportNotUniqueIdentifiersException; import com.aurel.track.fieldType.constants.BooleanFields; import com.aurel.track.fieldType.constants.SystemFields; import com.aurel.track.fieldType.runtime.bl.AttributeValueBL; import com.aurel.track.item.ItemBL; import com.aurel.track.item.ItemLoaderException; import com.aurel.track.item.ItemPersisterException; import com.aurel.track.item.workflow.execute.WorkflowContext; import com.aurel.track.lucene.index.LuceneIndexer; import com.aurel.track.tql.TqlBL; import com.aurel.track.util.DateTimeUtils; import com.aurel.track.util.EqualUtils; import com.aurel.track.util.GeneralUtils; import com.workingdogs.village.DataSetException; import com.workingdogs.village.Record; import com.workingdogs.village.Value; /** * * This class is the persistence layer proxy for the core objects in the * Genji system, the issues. * */ public class TWorkItemPeer extends com.aurel.track.persist.BaseTWorkItemPeer implements WorkItemDAO { private static final long serialVersionUID = 3300436877834074233L; private static final Logger LOGGER = LogManager.getLogger(TWorkItemPeer.class); private static final String failedWith = " failed with "; private static Class[] dependentPeerClasses = { TActualEstimatedBudgetPeer.class, TAttachmentPeer.class, TBaseLinePeer.class, TBudgetPeer.class, TCostPeer.class, TIssueAttributeValuePeer.class, TNotifyPeer.class, TStateChangePeer.class, TTrailPeer.class, TComputedValuesPeer.class, TAttributeValuePeer.class, TWorkItemLinkPeer.class, TWorkItemLinkPeer.class, TWorkItemLockPeer.class, THistoryTransactionPeer.class, TSummaryMailPeer.class, TMSProjectTaskPeer.class, TPersonBasketPeer.class, TLastVisitedItemPeer.class, TReadIssuePeer.class, TAttachmentVersionPeer.class, TItemTransitionPeer.class, //use the superclass doDelete() method!!! BaseTWorkItemPeer.class }; private static String[] fields = { TActualEstimatedBudgetPeer.WORKITEMKEY, TAttachmentPeer.WORKITEM, TBaseLinePeer.WORKITEMKEY, TBudgetPeer.WORKITEMKEY, TCostPeer.WORKITEM, TIssueAttributeValuePeer.ISSUE, TNotifyPeer.WORKITEM, TStateChangePeer.WORKITEMKEY, TTrailPeer.WORKITEMKEY, TComputedValuesPeer.WORKITEMKEY, TAttributeValuePeer.WORKITEM, TWorkItemLinkPeer.LINKPRED, TWorkItemLinkPeer.LINKSUCC, TWorkItemLockPeer.WORKITEM, THistoryTransactionPeer.WORKITEM, TSummaryMailPeer.WORKITEM, TMSProjectTaskPeer.WORKITEM, TPersonBasketPeer.WORKITEM, TLastVisitedItemPeer.WORKITEM, TReadIssuePeer.WORKITEM, TAttachmentVersionPeer.WORKITEM, TItemTransitionPeer.WORKITEM, BaseTWorkItemPeer.WORKITEMKEY }; /** * delete workItems with the given criteria and delete all dependent database entries * Called by reflection * @param crit */ public static void doDelete(Criteria crit) { try { // retrieve all the items first List<TWorkItem> list = doSelect(crit); if (list == null || list.isEmpty()) { return; } List<Integer> itemIDs = new ArrayList<Integer>(list.size()); for (TWorkItem tWorkItem : list) { itemIDs.add(tWorkItem.getObjectID()); } removeParents(itemIDs); List<Integer> itemPickerFields = FieldBL.getCustomPickerFieldIDs(SystemFields.INTEGER_ISSUENO); for (TWorkItem workItem : list) { Integer workItemID = workItem.getObjectID(); if (itemPickerFields != null && !itemPickerFields.isEmpty()) { for (Integer fieldID : itemPickerFields) { //Remove the occurrences of items in item pickers AttributeValueBL.deleteBySystemOption(fieldID, workItemID, SystemFields.INTEGER_ISSUENO); } } ReflectionHelper.delete(dependentPeerClasses, fields, workItemID); } } catch (TorqueException e) { LOGGER.error("Cascade deleteing the field configs failed with " + e.getMessage()); } } /** * Set the superior workItem to null for the child workItems of a deleted parent node * @param objectID */ private static void removeParents(List<Integer> itemIDs) { List<int[]> workItemIDChunksList = GeneralUtils.getListOfChunks(itemIDs); if (workItemIDChunksList == null) { return; } Iterator<int[]> iterator = workItemIDChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; int[] workItemIDChunk = (int[]) iterator.next(); Criteria selectCriteria = new Criteria(); selectCriteria.addIn(SUPERIORWORKITEM, workItemIDChunk); Criteria updateCriteria = new Criteria(); updateCriteria.add(SUPERIORWORKITEM, (Object) null, Criteria.ISNULL); try { doUpdate(selectCriteria, updateCriteria); } catch (TorqueException e) { LOGGER.error("Removing the deleted superior workItem from childen to be deleted at loop " + i + failedWith + e.getMessage()); } } } /************************************************************************ *************************Bean methods*********************************** ************************************************************************/ /** * Loads a priorityBean by primary key * @param objectID * @return */ @Override public TWorkItemBean loadByPrimaryKey(Integer objectID) throws ItemLoaderException { TWorkItem tWorkItem = null; try { tWorkItem = retrieveByPK(objectID); } catch (Exception e) { LOGGER.info("Loading the workItem by primary key " + objectID + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); throw new ItemLoaderException("Loading the workItem by " + objectID + " failed", e); } if (tWorkItem != null) { return tWorkItem.getBean(); } return null; } @Override public TWorkItemBean loadByProjectSpecificID(Integer projectID, Integer idNumber) throws ItemLoaderException { Criteria crit = new Criteria(); crit.add(PROJECTKEY, projectID); crit.add(IDNUMBER, idNumber); try { List<TWorkItem> torqueList = doSelect(crit); if (torqueList != null && !torqueList.isEmpty()) { return torqueList.get(0).getBean(); } } catch (TorqueException e) { LOGGER.error("loadByProjectSpecificID failed with " + e.getMessage()); } return null; } /** * Gets the list of workItems which should appear in the reminder email * @param personID * @param remindMeAsOriginator * @param remindMeAsManager * @param remindMeAsResponsible * @param dateLimit * @return */ @Override public List<TWorkItemBean> loadReminderWorkItems(Integer personID, String remindMeAsOriginator, String remindMeAsManager, String remindMeAsResponsible, Date dateLimit) { // now build the criteria Criteria crit = new Criteria(); Criterion raciCriterion = null; boolean first = true; if (remindMeAsOriginator != null && BooleanFields.TRUE_VALUE.equals(remindMeAsOriginator)) { LOGGER.debug("Adding originator"); raciCriterion = crit.getNewCriterion(ORIGINATOR, personID, Criteria.EQUAL); first = false; } if (remindMeAsManager != null && BooleanFields.TRUE_VALUE.equals(remindMeAsManager)) { if (first) { LOGGER.debug("Adding manager"); raciCriterion = crit.getNewCriterion(OWNER, personID, Criteria.EQUAL); first = false; } else { LOGGER.debug("ORing manager"); if (raciCriterion != null) { // just to disable compiler warning raciCriterion = raciCriterion.or(crit.getNewCriterion(OWNER, personID, Criteria.EQUAL)); } } } if (remindMeAsResponsible != null && BooleanFields.TRUE_VALUE.equals(remindMeAsResponsible)) { if (first) { LOGGER.debug("adding responsible"); raciCriterion = crit.getNewCriterion(RESPONSIBLE, personID, Criteria.EQUAL); } else { LOGGER.debug("ORing responsible"); if (raciCriterion != null) { // just to disable compiler warning raciCriterion = raciCriterion.or(crit.getNewCriterion(RESPONSIBLE, personID, Criteria.EQUAL)); } } } if (raciCriterion != null) { crit.add(raciCriterion); } else { crit.add(RESPONSIBLE, personID, Criteria.EQUAL); } Criterion endDatesCriterion = crit.getNewCriterion(ENDDATE, dateLimit, Criteria.LESS_EQUAL); endDatesCriterion.or(crit.getNewCriterion(TOPDOWNENDDATE, dateLimit, Criteria.LESS_EQUAL)); crit.add(endDatesCriterion); CriteriaUtil.addStateFlagUnclosedCriteria(crit); CriteriaUtil.addArchivedDeletedFilter(crit); CriteriaUtil.addActiveProjectCriteria(crit); //crit.add(TWorkItemPeer.ENDDATE, dateLimit, Criteria.LESS_EQUAL); crit.addDescendingOrderByColumn(ENDDATE); crit.addDescendingOrderByColumn(TOPDOWNENDDATE); LOGGER.debug(crit.toString()); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Getting the reminder workItems failed with " + e.getMessage()); return null; } } /** * Gets the number of entries in TWORKITEM. * @return number of table entries in TWORKITEM */ @Override public int count() { String COUNT = "count(" + WORKITEMKEY + ")"; Criteria crit = new Criteria(); // use empty Criteria to get all entries crit.addSelectColumn(COUNT); // SELECT count(WORKITEMKEY); try { return ((Record) doSelectVillageRecords(crit).get(0)).getValue(1).asInt(); } catch (TorqueException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } catch (DataSetException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } return 0; // get the one and only returned record. Get the first value in this record. // Record values index always starts at 1. } /** * Gets a workItem by secondary key values * @param identifierFieldValues * @return */ @Override public TWorkItemBean loadBySecondaryKeys(Map<Integer, Object> identifierFieldValues) throws ExcelImportNotUniqueIdentifiersException { List<TWorkItem> workItems = null; Criteria crit = new Criteria(); try { Object projectID = identifierFieldValues.get(SystemFields.INTEGER_PROJECT); if (projectID != null) { crit.add(PROJECTKEY, projectID); } Object releaseScheduled = identifierFieldValues.get(SystemFields.INTEGER_RELEASESCHEDULED); if (releaseScheduled != null) { crit.add(RELSCHEDULEDKEY, releaseScheduled); } Object releaseNoticed = identifierFieldValues.get(SystemFields.INTEGER_RELEASENOTICED); if (releaseNoticed != null) { crit.add(RELNOTICEDKEY, releaseNoticed); } Object managerID = identifierFieldValues.get(SystemFields.INTEGER_MANAGER); if (managerID != null) { crit.add(OWNER, managerID); } Object responsibleID = identifierFieldValues.get(SystemFields.INTEGER_RESPONSIBLE); if (responsibleID != null) { crit.add(RESPONSIBLE, responsibleID); } Object originatorID = identifierFieldValues.get(SystemFields.INTEGER_ORIGINATOR); if (originatorID != null) { crit.add(ORIGINATOR, originatorID); } Object changedByID = identifierFieldValues.get(SystemFields.INTEGER_CHANGEDBY); if (changedByID != null) { crit.add(CHANGEDBY, changedByID); } Object issueTypeID = identifierFieldValues.get(SystemFields.INTEGER_ISSUETYPE); if (issueTypeID != null) { crit.add(CATEGORYKEY, issueTypeID); } Object stateID = identifierFieldValues.get(SystemFields.INTEGER_STATE); if (stateID != null) { crit.add(STATE, stateID); } Object priorityID = identifierFieldValues.get(SystemFields.INTEGER_PRIORITY); if (priorityID != null) { crit.add(PRIORITYKEY, priorityID); } Object severityID = identifierFieldValues.get(SystemFields.INTEGER_SEVERITY); if (severityID != null) { crit.add(SEVERITYKEY, severityID); } Object synopsis = identifierFieldValues.get(SystemFields.INTEGER_SYNOPSIS); if (synopsis != null && !"".equals(synopsis)) { crit.add(PACKAGESYNOPSYS, synopsis); } Object createDate = identifierFieldValues.get(SystemFields.INTEGER_CREATEDATE); if (createDate != null) { crit.add(CREATED, createDate); } Object startDate = identifierFieldValues.get(SystemFields.INTEGER_STARTDATE); if (startDate != null) { crit.add(STARTDATE, startDate); } Object endDate = identifierFieldValues.get(SystemFields.INTEGER_ENDDATE); if (endDate != null) { crit.add(ENDDATE, endDate); } Object issueNo = identifierFieldValues.get(SystemFields.INTEGER_ISSUENO); if (issueNo != null) { crit.add(WORKITEMKEY, issueNo); } Object build = identifierFieldValues.get(SystemFields.INTEGER_BUILD); if (build != null && !"".equals(build)) { crit.add(BUILD, build); } Object submitterEmail = identifierFieldValues.get(SystemFields.INTEGER_SUBMITTEREMAIL); if (submitterEmail != null && !"".equals(submitterEmail)) { crit.add(SUBMITTEREMAIL, submitterEmail); } Object superiorWorkItem = identifierFieldValues.get(SystemFields.INTEGER_SUPERIORWORKITEM); if (superiorWorkItem != null) { crit.add(SUPERIORWORKITEM, superiorWorkItem); } //ReportBeanLoader.addArchivedDeletedFilter(crit); workItems = doSelect(crit); } catch (Exception e) { LOGGER.error("Getting the workItems by secondary keys failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } if (workItems == null || workItems.isEmpty()) { return null; } else { if (!workItems.isEmpty()) { LOGGER.debug("More than one workItems found for the secondary keys"); throw new ExcelImportNotUniqueIdentifiersException(workItems.size() + "workItems found"); } } return workItems.get(0).getBean(); } /** * Gets the list of all workItems * @return */ @Override public List<TWorkItemBean> loadAll() { Criteria crit = new Criteria(); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (Exception e) { LOGGER.error("Getting all workItems failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); return new LinkedList<TWorkItemBean>(); } } /** * Gets the list of all issues with parent. * @return */ @Override public List<TWorkItemBean> loadAllWithParent() { Criteria crit = new Criteria(); crit.add(SUPERIORWORKITEM, (Object) null, Criteria.ISNOTNULL); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (Exception e) { LOGGER.error("Getting all workItems with parent failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); return new LinkedList<TWorkItemBean>(); } } @Override public List<TWorkItemBean> getChildren(Integer key) { Criteria crit = new Criteria(); crit.add(BaseTWorkItemPeer.SUPERIORWORKITEM, key, Criteria.EQUAL); crit.addAscendingOrderByColumn(BaseTWorkItemPeer.WORKITEMKEY); CriteriaUtil.addArchivedDeletedFilter(crit); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the children by key " + key + failedWith + e); return null; } } /** * Gets the children of a issue array * @param workItemIDs * @param notClosed whether to get only the unclosed child issues, or all child issues * @param archived * @param deleted * @param itemTypesList * @return */ @Override public List<TWorkItemBean> getChildren(int[] workItemIDs, boolean notClosed, Integer archived, Integer deleted, List<Integer> itemTypesList) { List<TWorkItemBean> workItemList = new ArrayList<TWorkItemBean>(); if (workItemIDs == null || workItemIDs.length == 0) { return workItemList; } Criteria criteria; List<int[]> workItemIDChunksList = GeneralUtils.getListOfChunks(workItemIDs); if (workItemIDChunksList == null) { return workItemList; } Iterator<int[]> iterator = workItemIDChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; int[] workItemIDChunk = iterator.next(); criteria = new Criteria(); criteria.addIn(SUPERIORWORKITEM, workItemIDChunk); if (notClosed) { CriteriaUtil.addStateFlagUnclosedCriteria(criteria); } if (itemTypesList != null && !itemTypesList.isEmpty()) { criteria.addIn(CATEGORYKEY, itemTypesList); } CriteriaUtil.addArchivedCriteria(criteria, archived, deleted); try { workItemList.addAll(convertTorqueListToBeanList(doSelect(criteria))); } catch (Exception e) { LOGGER.error("Loading the workItemBeans by children and the chunk number " + i + " of length " + workItemIDChunk.length + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } } return workItemList; } /** * Gets the last workItem created by a person * @param personID * @return */ @Override public TWorkItemBean loadLastCreated(Integer personID) { Date createdDate = null; String max = "max(" + CREATED + ")"; Criteria criteria = new Criteria(); criteria.add(ORIGINATOR, personID); criteria.addSelectColumn(max); List<Record> records = null; try { records = doSelectVillageRecords(criteria); if (records != null && !records.isEmpty()) { Record record = records.get(0); if (record != null) { createdDate = record.getValue(1).asDate(); } } } catch (Exception e) { LOGGER.error("Getting the creation date of the last workItem created by person " + personID + " failed with: " + e); } List<TWorkItem> workItemList = null; if (createdDate != null) { createdDate = DateTimeUtils.clearDateSeconds(createdDate); criteria.clear(); criteria.add(ORIGINATOR, personID); criteria.add(CREATED, createdDate, Criteria.GREATER_EQUAL); criteria.addDescendingOrderByColumn(WORKITEMKEY); try { workItemList = doSelect(criteria); } catch (TorqueException e) { LOGGER.error("Getting the last workItem created by person " + personID + " failed with: " + e); } } if (workItemList != null && !workItemList.isEmpty()) { return ((TWorkItem) workItemList.get(0)).getBean(); } //} return null; } /** * Gets the last workItem created by a person for a project and issueType * When for the project-issueType is not found, get the last by project * @param personID * @param projectID * @param issueTypeID * @return */ @Override public TWorkItemBean loadLastCreatedByProjectIssueType(Integer personID, Integer projectID, Integer issueTypeID) { List<TWorkItem> workItemList = null; Criteria criteria = new Criteria(); criteria.add(PROJECTKEY, projectID); criteria.add(ORIGINATOR, personID); criteria.add(CATEGORYKEY, issueTypeID); criteria.addDescendingOrderByColumn(CREATED); criteria.setLimit(1); try { workItemList = doSelect(criteria); } catch (TorqueException e) { LOGGER.error("Getting the creation date of the last workItem by person " + personID + " project " + projectID + " failed with: " + e); } if (workItemList != null && !workItemList.isEmpty()) { return ((TWorkItem) workItemList.get(0)).getBean(); } criteria.clear(); criteria.add(PROJECTKEY, projectID); criteria.add(ORIGINATOR, personID); criteria.addDescendingOrderByColumn(CREATED); criteria.setLimit(1); try { workItemList = doSelect(criteria); } catch (TorqueException e) { LOGGER.error("Getting the creation date of the last workItem by person " + personID + " project " + projectID + " failed with: " + e); } if (workItemList != null && !workItemList.isEmpty()) { return ((TWorkItem) workItemList.get(0)).getBean(); } return null; } /** * Loads a WorkItemBean list by workItemKeys * @param workItemKeys * @return */ @Override public List<TWorkItemBean> loadByWorkItemKeys(int[] workItemKeys) { return loadByWorkItemKeys(workItemKeys, (Date) null, (Date) null); } @Override public List<TWorkItemBean> loadByWorkItemKeys(int[] workItemKeys, Date startDate, Date endDate) { List<TWorkItemBean> workItemList = new ArrayList<TWorkItemBean>(); if (workItemKeys == null || workItemKeys.length == 0) { return workItemList; } Criteria criteria; List<int[]> workItemIDChunksList = GeneralUtils.getListOfChunks(workItemKeys); if (workItemIDChunksList == null) { return workItemList; } Iterator<int[]> iterator = workItemIDChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; int[] workItemIDChunk = (int[]) iterator.next(); criteria = new Criteria(); criteria.addIn(WORKITEMKEY, workItemIDChunk); addDateCriteria(criteria, startDate, endDate); try { workItemList.addAll(convertTorqueListToBeanList(doSelect(criteria))); } catch (Exception e) { LOGGER.error("Loading the workItemBeans by workItemKeys and the chunk number " + i + " of length " + workItemIDChunk.length + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } } return workItemList; } /** * Loads a list with {@link TWorkItemBean}s as specified by the object identifiers in parameter. * @param workItemKeys - the array of object identifiers for the <code>TWorkItemBean</code>s to be retrieved. * @param archived * @param deleted * @return A list with {@link TWorkItemBean}s. */ @Override public List<TWorkItemBean> loadByWorkItemKeys(int[] workItemKeys, Integer archived, Integer deleted) { List<TWorkItemBean> workItemList = new ArrayList<TWorkItemBean>(); if (workItemKeys == null || workItemKeys.length == 0) { return workItemList; } Criteria criteria; List<int[]> workItemIDChunksList = GeneralUtils.getListOfChunks(workItemKeys); if (workItemIDChunksList == null) { return workItemList; } Iterator<int[]> iterator = workItemIDChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; int[] workItemIDChunk = (int[]) iterator.next(); criteria = new Criteria(); criteria.addIn(WORKITEMKEY, workItemIDChunk); CriteriaUtil.addArchivedCriteria(criteria, archived, deleted); try { workItemList.addAll(convertTorqueListToBeanList(doSelect(criteria))); } catch (Exception e) { LOGGER.error("Loading the workItemBeans by workItemKeys and the chunk number " + i + " of length " + workItemIDChunk.length + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } } return workItemList; } /** * Loads a list with {@link TWorkItemBean}s as specified by synopsis list in parameter. * @param workItemKeys - synopsisList * <p/> * @return A list with {@link TWorkItemBean}s. */ @Override public List<TWorkItemBean> loadBySynopsisList(List<String> synopsisList) { List<TWorkItemBean> workItemList = new ArrayList<TWorkItemBean>(); if (synopsisList == null || synopsisList.isEmpty()) { return workItemList; } Criteria criteria; List<List<String>> workItemSynopsisChunksList = GeneralUtils.getListOfStringChunks(synopsisList); if (workItemSynopsisChunksList == null) { return workItemList; } Iterator<List<String>> iterator = workItemSynopsisChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; List<String> workItemSynopsisChunk = iterator.next(); criteria = new Criteria(); criteria.addIn(PACKAGESYNOPSYS, workItemSynopsisChunk); try { workItemList.addAll(convertTorqueListToBeanList(doSelect(criteria))); } catch (Exception e) { LOGGER.error("Loading the workItemBeans by synopsis list and the chunk number " + i + " of length " + workItemSynopsisChunk.size() + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } } return workItemList; } /** * Loads a list with {@link TWorkItemBean}s as specified by the uuids in parameter. * @param uuids - the list of object uuids for the TWorkItemBeans to be retrieved. * <p/> * @return A list with {@link TWorkItemBean}s. */ @Override public List<TWorkItemBean> loadByUuids(List<String> uuids) { List<TWorkItemBean> workItemList = new ArrayList<TWorkItemBean>(); if (uuids == null || uuids.isEmpty()) { return workItemList; } Criteria criteria; List<List<String>> workItemIDChunksList = GeneralUtils.getListOfStringChunks(uuids); if (workItemIDChunksList == null) { return workItemList; } Iterator<List<String>> iterator = workItemIDChunksList.iterator(); int i = 0; while (iterator.hasNext()) { i++; List<String> workItemIDChunk = iterator.next(); criteria = new Criteria(); criteria.addIn(TPUUID, workItemIDChunk); try { workItemList.addAll(convertTorqueListToBeanList(doSelect(criteria))); } catch (Exception e) { LOGGER.error("Loading the workItemBeans by uuids and the chunk number " + i + " of length " + workItemIDChunk.size() + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } } return workItemList; } /** * Loads workItems for import which has associated msProjectTaskBean objects * and are of type task, include also the closed and deleted, archived tasks * @param entityID * @param entityType */ @Override public List<TWorkItemBean> loadMsProjectTasksForImport(Integer entityID, int entityType) { Criteria crit = new Criteria(); crit.addJoin(WORKITEMKEY, BaseTMSProjectTaskPeer.WORKITEM); crit.addJoin(CATEGORYKEY, BaseTListTypePeer.PKEY); crit.add(BaseTListTypePeer.TYPEFLAG, TListTypeBean.TYPEFLAGS.TASK); switch (entityType) { case SystemFields.RELEASESCHEDULED: crit.add(RELSCHEDULEDKEY, entityID); break; case SystemFields.PROJECT: crit.add(PROJECTKEY, entityID); break; default: return null; } try { return convertTorqueListToBeanList(doSelect(crit)); } catch (Exception e) { LOGGER.error("Loading WorkItems with task by entityID " + entityID + " entityType " + entityType + failedWith + e.getMessage()); return null; } } /** * Loads workItems for export which has associated msProjectTaskBean objects and are of type task * exclude the archived and deleted tasks and depending on "closed" also the closed tasks * @param entityID * @param entityType * @param notClosed * @return */ @Override public List<TWorkItemBean> loadMsProjectTasksForExport(Integer entityID, int entityType, boolean notClosed) { Criteria crit = new Criteria(); //left join because the new task workItems doesn't have TMSProjectTask pair yet crit.addJoin(WORKITEMKEY, BaseTMSProjectTaskPeer.WORKITEM, Criteria.LEFT_JOIN); crit.addJoin(CATEGORYKEY, BaseTListTypePeer.PKEY); crit.add(BaseTListTypePeer.TYPEFLAG, TListTypeBean.TYPEFLAGS.TASK); CriteriaUtil.addArchivedDeletedFilter(crit); if (notClosed) { CriteriaUtil.addStateFlagUnclosedCriteria(crit); } crit.addAscendingOrderByColumn(BaseTMSProjectTaskPeer.OUTLINENUMBER); //the new ones doesn't have outline number, they are ordered by creation date crit.addAscendingOrderByColumn(CREATED); switch (entityType) { case SystemFields.RELEASESCHEDULED: crit.add(RELSCHEDULEDKEY, entityID); break; case SystemFields.PROJECT: crit.add(PROJECTKEY, entityID); break; default: return null; } try { return convertTorqueListToBeanList(doSelect(crit)); } catch (Exception e) { LOGGER.error("Loading WorkItems with task by entityID " + entityID + " entityType " + entityType + failedWith + e.getMessage()); return null; } } /** * Loads all indexable workItems and sets the projectID fields * @return */ @Override public List<TWorkItemBean> loadIndexable() { //For example workItems from closed projects, closed workItems List<TWorkItemBean> workItemBeans = loadAll(); return workItemBeans; } /** * Gets the maximal objectID */ @Override public Integer getMaxObjectID() { String max = "max(" + WORKITEMKEY + ")"; Criteria crit = new Criteria(); crit.addSelectColumn(max); try { return ((Record) doSelectVillageRecords(crit).get(0)).getValue(1).asIntegerObj(); } catch (Exception e) { LOGGER.error("Getting the maximal workItemID failed with " + e.getMessage()); } return null; } /** * Gets the next chunk * @param actualValue * @param chunkInterval * @return */ @Override public List<TWorkItemBean> getNextChunk(Integer actualValue, Integer chunkInterval) { SimpleCriteria crit = new SimpleCriteria(); int toValue = actualValue.intValue() + chunkInterval.intValue(); crit.addIsBetween(WORKITEMKEY, actualValue.intValue(), toValue); crit.addAscendingOrderByColumn(LASTEDIT); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error( "Getting the workitems from " + actualValue + " to " + toValue + failedWith + e.getMessage()); return null; } } /** * Load the workItems by a systemListID depending on a systemListType * @param systemListType * @param systemListID * @return */ @Override public int[] loadBySystemList(int systemListType, Integer systemListID) { Criteria crit = new Criteria(); switch (systemListType) { case SystemFields.PROJECT: crit.add(PROJECTKEY, systemListID); break; case SystemFields.RELEASE: Criterion relNoticed = crit.getNewCriterion(RELNOTICEDKEY, systemListID, Criteria.EQUAL); Criterion relScheduled = crit.getNewCriterion(RELSCHEDULEDKEY, systemListID, Criteria.EQUAL); crit.add(relNoticed.or(relScheduled)); break; case SystemFields.ISSUETYPE: crit.add(CATEGORYKEY, systemListID); break; case SystemFields.STATE: crit.add(STATE, systemListID); break; case SystemFields.PRIORITY: crit.add(PRIORITYKEY, systemListID); break; case SystemFields.SEVERITY: crit.add(SEVERITYKEY, systemListID); break; default: return null; } crit.addSelectColumn(WORKITEMKEY); List<Record> torqueList = null; try { torqueList = doSelectVillageRecords(crit); } catch (TorqueException e) { LOGGER.error("Loading workItemIDs by systemListType " + systemListType + " and systemListID " + systemListID + failedWith + e); } int[] workItemIDs = null; if (torqueList != null) { workItemIDs = new int[torqueList.size()]; for (int i = 0; i < torqueList.size(); i++) { Record record = (Record) torqueList.get(i); try { workItemIDs[i] = record.getValue(1).asInt(); } catch (DataSetException e) { LOGGER.error("Getting the workItemIDs by systemListType " + systemListType + " and systemListID " + systemListID + failedWith + e); } } } return workItemIDs; } /** * Get all the issue from an project, include the closed/archived/deleted issues. */ @Override public List<TWorkItemBean> loadAllByProject(Integer projectID, Integer archived, Integer deleted) { Criteria crit = new Criteria(); crit.add(PROJECTKEY, projectID); crit.addAscendingOrderByColumn(WORKITEMKEY); CriteriaUtil.addArchivedCriteria(crit, archived, deleted); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading all workItems by project " + projectID + failedWith + e.getMessage()); return null; } } Object mutex = new Object(); /** * Saves a workItemBean in the TWorkItem table and creates/updates a lucene Document for it. * Be sure that the TWorkItem.save() is not called directly from other program code, * because then no lucene indexing takes place!!! * @param workItemBean */ @Override public Integer save(TWorkItemBean workItemBean) throws ItemPersisterException { boolean isNew = false; Integer objectID = null; Integer idNumber = null; try { isNew = workItemBean.getObjectID() == null || workItemBean.getObjectID().intValue() == -1; TWorkItem tWorkItem = BaseTWorkItem.createTWorkItem(workItemBean); if (isNew) { synchronized (mutex) { Integer projectID = tWorkItem.getProjectID(); Integer nextWBS = getNextWbsOnLevel(tWorkItem.getSuperiorworkitem(), projectID); tWorkItem.setWBSOnLevel(nextWBS); idNumber = calculateIDNumber(projectID, tWorkItem); } } else { tWorkItem.save(); } objectID = tWorkItem.getObjectID(); LOGGER.debug("WorkItem with ID " + objectID + " saved "); } catch (Exception e) { LOGGER.error("Saving the workItem " + workItemBean.getObjectID() + " with synopsis " + workItemBean.getSynopsis() + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); throw new ItemPersisterException("Saving the workItem " + workItemBean.getObjectID() + " with synopsis " + workItemBean.getSynopsis() + " failed", e); } try { //objectID null means that the save doesn't succeeded if (objectID != null) { if (isNew) { workItemBean.setObjectID(objectID); workItemBean.setIDNumber(idNumber); } LuceneIndexer.addToWorkItemIndex(workItemBean, !isNew); //possible lucene update in other cluster nodes ClusterMarkChangesBL.markDirtyWorkitemInCluster(objectID, ClusterMarkChangesBL.getChangeTypeByAddOrUpdateIndex(isNew)); } } catch (Exception e) { LOGGER.error("Saving the workitem in lucene index failed with " + e.getMessage()); } return objectID; } /** * Calculates the project specific IDNumber * If tWorkItem is specified then it is saved after setting the calculated IDNumber * Otherwise only returns the IDNumber * @param projectID * @param tWorkItem * @return */ private static synchronized Integer calculateIDNumber(Integer projectID, TWorkItem tWorkItem) { Integer nextItemID = null; if (projectID != null) { Connection connection = null; try { connection = Transaction.begin(DATABASE_NAME); } catch (TorqueException e) { LOGGER.error("Getting the connection for failed with " + e.getMessage()); return null; } if (connection != null) { try { TProject tProject = null; try { tProject = TProjectPeer.retrieveByPK(projectID, connection); } catch (Exception e) { LOGGER.error( "Loading of a project by primary key " + projectID + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } if (tProject != null) { nextItemID = tProject.getNextItemID(); if (nextItemID == null) { nextItemID = getNextItemID(projectID); } if (tWorkItem != null) { tWorkItem.setIDNumber(nextItemID); tWorkItem.save(connection); } tProject.setNextItemID(nextItemID.intValue() + 1); TProjectPeer.doUpdate(tProject, connection); Transaction.commit(connection); } connection = null; } catch (Exception e) { LOGGER.error("Setting the project specific itemID failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } finally { if (connection != null) { Transaction.safeRollback(connection); } } } } return nextItemID; } /** * Saves a workItemBean in the TWorkItem table without lucene update. * @param workItemBean */ @Override public Integer saveSimple(TWorkItemBean workItemBean) throws ItemPersisterException { Integer objectID = null; try { TWorkItem tWorkItem = BaseTWorkItem.createTWorkItem(workItemBean); tWorkItem.save(); objectID = tWorkItem.getObjectID(); LOGGER.debug("WorkItem with ID " + objectID + " saved "); } catch (Exception e) { LOGGER.error("Saving the workItem " + workItemBean.getObjectID() + " with synopsis " + workItemBean.getSynopsis() + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); throw new ItemPersisterException("Saving the workItem " + workItemBean.getObjectID() + " with synopsis " + workItemBean.getSynopsis() + " failed", e); } return objectID; } /** * Whether the item has open children besides exceptChildrenIDs * @param objectID * @return */ @Override public List<TWorkItemBean> getOpenChildren(Integer objectID, List<Integer> exceptChildrenIDs) { Criteria crit = new Criteria(); crit.add(SUPERIORWORKITEM, objectID); crit.addJoin(STATE, TStatePeer.PKEY); crit.add(TStatePeer.STATEFLAG, TStateBean.STATEFLAGS.CLOSED, Criteria.NOT_EQUAL); if (exceptChildrenIDs != null && !exceptChildrenIDs.isEmpty()) { crit.addNotIn(WORKITEMKEY, exceptChildrenIDs); } CriteriaUtil.addArchivedDeletedFilter(crit); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Getting the open children failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); return null; } } /** * Is any workItem from the array still open? * @param workItemIDs * @return */ @Override public boolean isAnyWorkItemOpen(int[] workItemIDs) { if (workItemIDs == null || workItemIDs.length == 0) { return false; } Criteria crit = new Criteria(); crit.addIn(WORKITEMKEY, workItemIDs); crit.addJoin(STATE, BaseTStatePeer.PKEY); crit.add(BaseTStatePeer.STATEFLAG, TStateBean.STATEFLAGS.CLOSED, Criteria.NOT_EQUAL); CriteriaUtil.addArchivedDeletedFilter(crit); List<TWorkItem> list = null; try { list = doSelect(crit); } catch (TorqueException e) { LOGGER.error("Getting the open children failed with " + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); } return list != null && !list.isEmpty(); } /** * Returns a deep copy of the workItemBean * @param workItemBean * @return */ @Override public TWorkItemBean copyDeep(TWorkItemBean workItemBean) { TWorkItem tWorkItemOriginal = null; try { tWorkItemOriginal = BaseTWorkItem.createTWorkItem(workItemBean); } catch (TorqueException e1) { LOGGER.error("Getting the torque object from bean failed with " + e1.getMessage()); } TWorkItem tWorkItemCopy = null; if (tWorkItemOriginal != null) { try { tWorkItemCopy = tWorkItemOriginal.copy(true); } catch (TorqueException e2) { LOGGER.error("Deep copy failed with " + e2.getMessage()); } } if (tWorkItemCopy != null) { return tWorkItemCopy.getBean(); } else { return null; } } /** * Get a list of workItemBeans according to a prepared critera * @param criteria * @return */ public static List<TWorkItemBean> getWorkItemBeansByCriteria(Criteria criteria) { try { return convertTorqueListToBeanList(doSelect(criteria)); } catch (TorqueException e) { LOGGER.error("Loading the workItems by criteria " + criteria.toString() + failedWith + e.getMessage()); return null; } } /********************************************************* * Manager-, Responsible-, My- and Custom Reports methods * *********************************************************/ public static void addDateCriteria(Criteria crit, Date startDate, Date endDate) { if (startDate == null && endDate == null) { return; } if (startDate != null && endDate != null) { // criteria for start date Criteria.Criterion cStartDateMin = crit.getNewCriterion(STARTDATE, startDate, Criteria.GREATER_EQUAL); Criteria.Criterion cStartDateMax = crit.getNewCriterion(STARTDATE, endDate, Criteria.LESS_EQUAL); Criteria.Criterion cStartDateAnd = cStartDateMin.and(cStartDateMax); // criteria for topdown start date Criteria.Criterion cTopDownStartDateMin = crit.getNewCriterion(TOPDOWNSTARTDATE, startDate, Criteria.GREATER_EQUAL); Criteria.Criterion cTopDownStartDateMax = crit.getNewCriterion(TOPDOWNSTARTDATE, endDate, Criteria.LESS_EQUAL); Criteria.Criterion cTopDownStartDateAnd = cTopDownStartDateMin.and(cTopDownStartDateMax); // criteria for end date Criteria.Criterion cEndDateMin = crit.getNewCriterion(ENDDATE, startDate, Criteria.GREATER_EQUAL); Criteria.Criterion cEndDateMax = crit.getNewCriterion(ENDDATE, endDate, Criteria.LESS_EQUAL); Criteria.Criterion cEndDateAnd = cEndDateMin.and(cEndDateMax); // criteria for topDown end date Criteria.Criterion cTopDownEndDateMin = crit.getNewCriterion(TOPDOWNENDDATE, startDate, Criteria.GREATER_EQUAL); Criteria.Criterion cTopDownEndDateMax = crit.getNewCriterion(TOPDOWNENDDATE, endDate, Criteria.LESS_EQUAL); Criteria.Criterion cTopDownEndDateAnd = cTopDownEndDateMin.and(cTopDownEndDateMax); // or criteria for start and end date Criteria.Criterion cDateOr = cStartDateAnd.or(cEndDateAnd).or(cTopDownStartDateAnd) .or(cTopDownEndDateAnd); crit.add(cDateOr); } else { if (startDate != null) { // criteria for start date Criteria.Criterion cStartDateMin = crit.getNewCriterion(STARTDATE, startDate, Criteria.GREATER_EQUAL); // criteria for TopDown start date Criteria.Criterion cTopDownStartDateMin = crit.getNewCriterion(TOPDOWNSTARTDATE, startDate, Criteria.GREATER_EQUAL); // criteria for end date Criteria.Criterion cEndDateMin = crit.getNewCriterion(ENDDATE, startDate, Criteria.GREATER_EQUAL); // criteria for TopDown end date Criteria.Criterion cTopDownEndDateMin = crit.getNewCriterion(TOPDOWNENDDATE, startDate, Criteria.GREATER_EQUAL); // or criteria for start and end date Criteria.Criterion cDateOr = cStartDateMin.or(cEndDateMin).or(cTopDownStartDateMin) .or(cTopDownEndDateMin); crit.add(cDateOr); } if (endDate != null) { // criteria for start date Criteria.Criterion cStartDateMax = crit.getNewCriterion(STARTDATE, endDate, Criteria.LESS_EQUAL); // criteria for TopDownstart date Criteria.Criterion cTopDownStartDateMax = crit.getNewCriterion(TOPDOWNSTARTDATE, endDate, Criteria.LESS_EQUAL); // criteria for end date Criteria.Criterion cEndDateMax = crit.getNewCriterion(ENDDATE, endDate, Criteria.LESS_EQUAL); // criteria for TopDown end date Criteria.Criterion cTopDownEndDateMax = crit.getNewCriterion(TOPDOWNENDDATE, endDate, Criteria.LESS_EQUAL); // or criteria for start and end date Criteria.Criterion cDateOr = cStartDateMax.or(cEndDateMax).or(cTopDownStartDateMax) .or(cTopDownEndDateMax); crit.add(cDateOr); } } } /** * Count the number of items in InBasket * @param personID * @return */ @Override public Integer countResponsibleWorkItems(Integer personID) { Criteria crit = ResponsibleCriteria.prepareResponsibleCriteria(personID); String COUNT = "count(" + WORKITEMKEY + ")"; crit.addSelectColumn(COUNT); try { return ((Record) doSelectVillageRecords(crit).get(0)).getValue(1).asInt(); } catch (TorqueException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } catch (DataSetException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } return 0; } /** * Get the workItemBeans the person is responsible for * If project is not null then just for that project * @param personID * @param project * @param entityFlag the meaning of the project: can be project, release, subproject etc. * @return */ @Override public List<TWorkItemBean> loadResponsibleWorkItems(Integer personID) { Criteria crit = ResponsibleCriteria.prepareResponsibleCriteria(personID); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the responsible workItems for person " + personID + failedWith + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Get meetings workItemBeans the person * is manager or responsible or owner for * If project is not null then just for that project/release * @param personID * @param project * @param entityFlag the meaning of the project: can be project, release, subproject etc. * @return */ @Override public List<TWorkItemBean> loadOrigManRespMeetings(Integer personID, Integer[] projectIDs, Integer[] releaseIDs) { Criteria crit = MeetingCriteria.prepareOrigManRespMeetingsCriteria(personID, projectIDs, releaseIDs); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the my workItems for person " + personID + failedWith + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Get meetings workItemBeans the person * is consulted or informed for * If project is not null then just for that project/release * @param personID * @param project * @param entityFlag the meaning of the project: can be project, release, subproject etc. * @return */ @Override public List<TWorkItemBean> loadConsInfMeetings(Integer personID, Integer[] projectIDs, Integer[] releaseIDs) { Criteria crit = MeetingCriteria.prepareConsInfMeetingsCriteria(personID, projectIDs, releaseIDs); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the my workItems for person " + personID + failedWith + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Get the workItemBeans filtered by the FilterSelectsTO * @param filterSelectsTO * @return */ @Override public Set<Integer> loadParentsInContext(Integer[] projectIDs, Integer itemTypeID) { Set<Integer> parentIDSet = new HashSet<Integer>(); Criteria crit = new Criteria(); String parent = "PARENT"; String child = "CHILD"; crit.addAlias(parent, TWorkItemPeer.TABLE_NAME); crit.addAlias(child, TWorkItemPeer.TABLE_NAME); crit.addJoin(parent + ".WORKITEMKEY", child + ".SUPERIORWORKITEM"); if (projectIDs != null && projectIDs.length != 0) { crit.addIn(parent + ".PROJECTKEY", projectIDs); } if (itemTypeID != null) { crit.add(parent + ".CATEGORYKEY", itemTypeID); } crit.addSelectColumn(parent + ".WORKITEMKEY"); crit.setDistinct(); List<Record> records = null; try { records = doSelectVillageRecords(crit); } catch (TorqueException e) { LOGGER.error("Loading the context items with parent failed with " + e.getMessage()); return parentIDSet; } try { if (records != null && !records.isEmpty()) { for (Record record : records) { Integer workItemID = record.getValue(1).asIntegerObj(); parentIDSet.add(workItemID); } } } catch (Exception e) { LOGGER.error("Getting the parent itemID failed with " + e.getMessage()); } return parentIDSet; } /** * Count the number of filter items * @param filterUpperTO * @param raciBean * @param personID * @return */ @Override public Integer countTreeFilterItems(FilterUpperTO filterUpperTO, RACIBean raciBean, Integer personID) { Integer[] selectedProjects = filterUpperTO.getSelectedProjects(); if (selectedProjects == null || selectedProjects.length == 0) { //at least one selected project needed return 0; } Criteria crit = TreeFilterCriteria.prepareTreeFilterCriteria(filterUpperTO, raciBean, personID); if (LOGGER.isDebugEnabled()) { LOGGER.debug(crit.toString()); } String COUNT = "count(" + WORKITEMKEY + ")"; crit.addSelectColumn(COUNT); try { return ((Record) doSelectVillageRecords(crit).get(0)).getValue(1).asInt(); } catch (TorqueException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } catch (DataSetException e) { LOGGER.error("Counting the workItems failed with " + e.getMessage()); } return 0; } @Override public List<TWorkItemBean> loadTreeFilterItems(FilterUpperTO filterUpperTO, RACIBean raciBean, Integer personID, Date startDate, Date endDate) { Integer[] selectedProjects = filterUpperTO.getSelectedProjects(); if (selectedProjects == null || selectedProjects.length == 0) { //at least one selected project needed return new ArrayList<TWorkItemBean>(); } Criteria crit = TreeFilterCriteria.prepareTreeFilterCriteria(filterUpperTO, raciBean, personID); if (LOGGER.isDebugEnabled()) { LOGGER.debug(crit.toString()); } addDateCriteria(crit, startDate, endDate); try { return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the custom report workItems failed with " + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Gets the itemIDs filtered by filterSelectsTO and raciBean which are parents * @param filterSelectsTO * @param raciBean * @param personID * @param startDate * @param enddDate * @return */ @Override public Set<Integer> loadTreeFilterParentIDs(FilterUpperTO filterSelectsTO, RACIBean raciBean, Integer personID, Date startDate, Date endDate) { Integer[] selectedProjects = filterSelectsTO.getSelectedProjects(); if (selectedProjects == null || selectedProjects.length == 0) { //at least one selected project needed return new HashSet<Integer>(); } Criteria crit = TreeFilterCriteria.prepareTreeFilterCriteria(filterSelectsTO, raciBean, personID); addDateCriteria(crit, startDate, endDate); return getParentItems(crit); } /** * Gets the itemIDs of those items which have children * @param crit * @return */ private static Set<Integer> getParentItems(Criteria crit) { Set<Integer> parentIDSet = new HashSet<Integer>(); String parent = TWorkItemPeer.TABLE_NAME;//"PARENT"; String child = "CHILD"; crit.addAlias(parent, TWorkItemPeer.TABLE_NAME); crit.addAlias(child, TWorkItemPeer.TABLE_NAME); crit.addJoin(parent + ".WORKITEMKEY", child + ".SUPERIORWORKITEM"); crit.addSelectColumn(parent + ".WORKITEMKEY"); //crit.setDistinct(); List<Record> records = null; try { records = doSelectVillageRecords(crit); } catch (TorqueException e) { LOGGER.error("Loading the context items with parent failed with " + e.getMessage()); return parentIDSet; } try { if (records != null && !records.isEmpty()) { for (Record record : records) { Integer workItemID = record.getValue(1).asIntegerObj(); parentIDSet.add(workItemID); } } } catch (Exception e) { LOGGER.error("Getting the parent itemID failed with " + e.getMessage()); } return parentIDSet; } /** * Loads the items filtered by a TQL expression * @param filterString * @param personBean * @param locale * @param errors * @param startDate * @param endDate * @return */ @Override public List<TWorkItemBean> loadTQLFilterItems(String filterString, TPersonBean personBean, Locale locale, List<ErrorData> errors, Date startDate, Date endDate) { Criteria tqlCriteria = TqlBL.createCriteria(filterString, personBean, locale, errors); addDateCriteria(tqlCriteria, startDate, endDate); try { return convertTorqueListToBeanList(doSelect(tqlCriteria)); } catch (TorqueException e) { LOGGER.error("Loading the TQL workItems failed with " + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Loads the itemIDs filtered by a TQL expression which are parents * @param filterString * @param personBean * @param locale * @param errors * @return */ @Override public Set<Integer> loadTQLFilterParentIDs(String filterString, TPersonBean personBean, Locale locale, List<ErrorData> errors) { Criteria tqlCriteria = TqlBL.createCriteria(filterString, personBean, locale, errors); return getParentItems(tqlCriteria); } /** /** * Load projectsIDs where the user has * originator/manager/responsible role for at least one workItem * @param meAndMySubstituted * @param meAndMySubstitutedAndGroups * @return */ @Override public Set<Integer> loadOrigManRespProjects(List<Integer> meAndMySubstituted, List<Integer> meAndMySubstitutedAndGroups) { Criteria criteria = new Criteria(); Criterion originator = criteria.getNewCriterion(TWorkItemPeer.ORIGINATOR, meAndMySubstituted, Criteria.IN); Criterion manager = criteria.getNewCriterion(TWorkItemPeer.OWNER, meAndMySubstituted, Criteria.IN); Criterion responsible = criteria.getNewCriterion(TWorkItemPeer.RESPONSIBLE, meAndMySubstitutedAndGroups, Criteria.IN); criteria.add(originator.or(manager).or(responsible)); return getProjectIDs(criteria, "originator/manager/responsible"); } /** * Load projectsIDs where the user has consultant/informant * role for at least one workItem * @param meAndMySubstitutedAndGroups * @return */ @Override public Set<Integer> loadConsultantInformantProjects(List<Integer> meAndMySubstitutedAndGroups) { Criteria criteria = new Criteria(); criteria.addJoin(TWorkItemPeer.WORKITEMKEY, TNotifyPeer.WORKITEM); criteria.addIn(TNotifyPeer.PERSONKEY, meAndMySubstitutedAndGroups); //criteria.addIn(TNotifyPeer.RACIROLE, new String[] {RaciRole.CONSULTANT, RaciRole.INFORMANT}); return getProjectIDs(criteria, "consultant/informant"); } /** * Load the not closed projects where the user has on behalf of * role for at least one workItem * @param meAndMySubstitutedAndGroups * @return */ @Override public Set<Integer> loadOnBehalfOfProjects(List<Integer> meAndMySubstitutedAndGroups, List<Integer> onBehalfPickerFieldIDs) { Criteria criteria = new Criteria(); criteria.addJoin(TWorkItemPeer.WORKITEMKEY, TAttributeValuePeer.WORKITEM); criteria.addIn(TAttributeValuePeer.FIELDKEY, onBehalfPickerFieldIDs); criteria.addIn(TAttributeValuePeer.SYSTEMOPTIONID, meAndMySubstitutedAndGroups); return getProjectIDs(criteria, "on behalf of"); } /** * Gets the projectIDs from resultset * @param criteria * @param raciRoles * @return */ private static Set<Integer> getProjectIDs(Criteria criteria, String raciRoles) { Set<Integer> projectIDs = new HashSet<Integer>(); try { criteria.addSelectColumn(PROJECTKEY); criteria.setDistinct(); List<Record> projectIDRecords = doSelectVillageRecords(criteria); if (projectIDRecords != null) { for (Record record : projectIDRecords) { try { Value value = record.getValue(1); if (value != null) { Integer projectID = value.asIntegerObj(); if (projectID != null) { projectIDs.add(projectID); } } } catch (DataSetException e) { LOGGER.error("Getting the projectID failed with " + e.getMessage()); } } } } catch (TorqueException e) { LOGGER.error("Loading of " + raciRoles + " projects failed with " + e.getMessage()); } return projectIDs; } /** * Convert the torque object list into bean list * @param torqueList * @return */ public static List<TWorkItemBean> convertTorqueListToBeanList(List<TWorkItem> torqueList) { List<TWorkItemBean> beanList = new ArrayList<TWorkItemBean>(); if (torqueList != null) { Iterator<TWorkItem> itrTorqueList = torqueList.iterator(); while (itrTorqueList.hasNext()) { beanList.add(itrTorqueList.next().getBean()); } } return beanList; } /** * sets the wbs for the entire project * @param projectID */ @Override public void setWbs(Integer projectID) { Criteria crit = new Criteria(); crit.add(PROJECTKEY, projectID); //in the case that the wbs got corrupted but still a wbs existed before try to preserve the order crit.addAscendingOrderByColumn(WBSONLEVEL); //if wbs does not exist then fall back to workItemKey as wbs crit.addAscendingOrderByColumn(WORKITEMKEY); List<TWorkItem> workItems = null; try { workItems = doSelect(crit); } catch (TorqueException e) { LOGGER.error("Loading the workItems by project " + projectID + failedWith + e.getMessage()); } Map<Integer, List<Integer>> childerenIDsForParentIDsMap = new HashMap<Integer, List<Integer>>(); Map<Integer, TWorkItem> workItemsMap = new HashMap<Integer, TWorkItem>(); List<Integer> rootItems = new ArrayList<Integer>(); if (workItems != null) { for (TWorkItem workItem : workItems) { Integer workItemID = workItem.getObjectID(); workItemsMap.put(workItemID, workItem); Integer parentID = workItem.getSuperiorworkitem(); if (parentID == null) { rootItems.add(workItemID); } else { List<Integer> children = childerenIDsForParentIDsMap.get(parentID); if (children == null) { children = new LinkedList<Integer>(); childerenIDsForParentIDsMap.put(parentID, children); } children.add(workItemID); } } } setWbsOnLevel(workItemsMap, rootItems); for (Integer parentIDs : childerenIDsForParentIDsMap.keySet()) { List<Integer> childrenIDs = childerenIDsForParentIDsMap.get(parentIDs); setWbsOnLevel(workItemsMap, childrenIDs); } } /** * Sets the wbs on a level * @param workItemsMap * @param workItemsOnSameLevel */ private static void setWbsOnLevel(Map<Integer, TWorkItem> workItemsMap, List<Integer> workItemsOnSameLevel) { if (workItemsOnSameLevel != null) { for (int i = 0; i < workItemsOnSameLevel.size(); i++) { Integer workItemID = workItemsOnSameLevel.get(i); TWorkItem workItem = workItemsMap.get(workItemID); if (workItem != null) { int wbs = i + 1; //save only if differs: avoid the expensive save operations if the value is already set if (workItem.getWBSOnLevel() == null || workItem.getWBSOnLevel().intValue() != wbs) { workItem.setWBSOnLevel(wbs); try { workItem.save(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Set the WBS " + wbs + " for workItem " + workItemID); } } catch (Exception e) { LOGGER.error("Setting the WBS " + wbs + failedWith + e.getMessage()); } } } } } } /** * Sets the wbs on the affected workItems after a drag and drop operation * @param draggedWorkItemID * @param droppedToWorkItemID * @param before */ @Override public synchronized void dropNearWorkItem(Integer draggedWorkItemID, Integer droppedToWorkItemID, boolean before) { TWorkItemBean workItemBeanDragged = null; try { workItemBeanDragged = loadByPrimaryKey(draggedWorkItemID); } catch (ItemLoaderException e1) { LOGGER.warn("The fromWorkItemID " + draggedWorkItemID + " does not exist"); return; } TWorkItemBean workItemBeanDroppedTo = null; try { workItemBeanDroppedTo = loadByPrimaryKey(droppedToWorkItemID); } catch (ItemLoaderException e1) { LOGGER.warn("The toWorkItemID " + droppedToWorkItemID + " does not exist"); return; } Integer projectID = workItemBeanDragged.getProjectID(); if (projectID == null) { LOGGER.warn("No project found for " + draggedWorkItemID + " does not exist"); return; } if (workItemBeanDragged.getWBSOnLevel() == null || workItemBeanDroppedTo.getWBSOnLevel() == null) { setWbs(projectID); try { //load them again this time with wbs numbers set workItemBeanDragged = loadByPrimaryKey(draggedWorkItemID); workItemBeanDroppedTo = loadByPrimaryKey(droppedToWorkItemID); } catch (ItemLoaderException e) { } } if (!projectID.equals(workItemBeanDroppedTo.getProjectID())) { LOGGER.debug("The drop target is not from the same project: abort drop"); return; } Integer parentOfDraggedWorkItem = workItemBeanDragged.getSuperiorworkitem(); Integer parentOfDroppedToWorkItem = workItemBeanDroppedTo.getSuperiorworkitem(); Integer draggedSortOrder = workItemBeanDragged.getWBSOnLevel(); Integer droppedToSortOrder = workItemBeanDroppedTo.getWBSOnLevel(); if (draggedSortOrder == null || droppedToSortOrder == null) { LOGGER.warn("The draggedSortOrder " + draggedSortOrder + " droppedToSortOrder " + droppedToSortOrder); return; } String sqlStmt = null; String droppedCriteria = ""; String draggedCriteria = ""; Integer workItemSortOrder; boolean parentsNull = parentOfDraggedWorkItem == null && parentOfDroppedToWorkItem == null; boolean parentsNotNull = parentOfDraggedWorkItem != null && parentOfDroppedToWorkItem != null; if (parentsNull || (parentsNotNull && parentOfDraggedWorkItem != null && parentOfDraggedWorkItem.equals(parentOfDroppedToWorkItem))) { if (draggedSortOrder.equals(droppedToSortOrder)) { //on the same level the same sortorder, not a real move, do nothing LOGGER.debug("The draggedSortOrder " + draggedSortOrder + " equals droppedToSortOrder " + droppedToSortOrder); return; } String parentCriteria = ""; //same level: both parent null or same parent if (parentsNotNull) { parentCriteria = " AND SUPERIORWORKITEM = " + parentOfDraggedWorkItem; } else { parentCriteria = " AND SUPERIORWORKITEM IS NULL "; } int inc = 0; if (draggedSortOrder > droppedToSortOrder) { inc = 1; if (before) { droppedCriteria = " AND WBSONLEVEL >= " + droppedToSortOrder; draggedCriteria = " AND WBSONLEVEL < " + draggedSortOrder; workItemSortOrder = droppedToSortOrder; } else { droppedCriteria = " AND WBSONLEVEL > " + droppedToSortOrder; draggedCriteria = " AND WBSONLEVEL < " + draggedSortOrder; workItemSortOrder = droppedToSortOrder + 1; } } else { inc = -1; if (before) { droppedCriteria = " AND WBSONLEVEL < " + droppedToSortOrder; draggedCriteria = " AND WBSONLEVEL > " + draggedSortOrder; workItemSortOrder = droppedToSortOrder - 1; } else { droppedCriteria = " AND WBSONLEVEL <= " + droppedToSortOrder; draggedCriteria = " AND WBSONLEVEL > " + draggedSortOrder; workItemSortOrder = droppedToSortOrder; } } sqlStmt = "UPDATE TWORKITEM SET WBSONLEVEL = WBSONLEVEL " + " + " + inc + " WHERE " + " PROJECTKEY = " + projectID + parentCriteria + draggedCriteria + droppedCriteria; executeStatemant(sqlStmt); } else { if (EqualUtils.equal(draggedWorkItemID, parentOfDroppedToWorkItem)) { LOGGER.warn("The WBS change would cause the issue " + draggedWorkItemID + " to became parent of itself"); //avoid same parentID as issueID return; } if (ItemBL.isAscendant(draggedWorkItemID, parentOfDroppedToWorkItem)) { LOGGER.warn("The chosen parent " + parentOfDroppedToWorkItem + " is already a descendant of the " + draggedWorkItemID); return; } //different levels //1. remove the dragged item from the original position and shift the following items up shiftBranch(draggedSortOrder, parentOfDraggedWorkItem, projectID, false); //2. shift down the actual items in the new place to make space for the dragged item to the new position String parentCriteriaOfDroppedItem = ""; if (parentOfDroppedToWorkItem != null) { parentCriteriaOfDroppedItem = " AND SUPERIORWORKITEM = " + parentOfDroppedToWorkItem; } else { parentCriteriaOfDroppedItem = " AND SUPERIORWORKITEM IS NULL "; } if (before) { droppedCriteria = " AND WBSONLEVEL >= " + droppedToSortOrder; workItemSortOrder = droppedToSortOrder; } else { droppedCriteria = " AND WBSONLEVEL > " + droppedToSortOrder; workItemSortOrder = droppedToSortOrder + 1; } sqlStmt = "UPDATE TWORKITEM SET WBSONLEVEL = WBSONLEVEL" + "+1 " + " WHERE " + " PROJECTKEY = " + projectID + parentCriteriaOfDroppedItem + droppedCriteria; executeStatemant(sqlStmt); workItemBeanDragged.setSuperiorworkitem(parentOfDroppedToWorkItem); } workItemBeanDragged.setWBSOnLevel(workItemSortOrder); try { saveSimple(workItemBeanDragged); } catch (ItemPersisterException e) { LOGGER.error("Saving the new droppedToSortOrder " + droppedToSortOrder + " for workItemID " + draggedWorkItemID + failedWith + e.getMessage(), e); } } /** * The parent was changed: recalculate the WBS both the old parent and the new parent can be null * @param workItemBean * @param workItemBeanOriginal * @param contextInformation */ @Override public void parentChanged(TWorkItemBean workItemBean, TWorkItemBean workItemBeanOriginal, Map<String, Object> contextInformation) { if (workItemBeanOriginal == null) { //new item return; } Integer oldParent = workItemBeanOriginal.getSuperiorworkitem(); Integer newParent = workItemBean.getSuperiorworkitem(); if ((oldParent == null && newParent == null) || (oldParent != null && newParent != null && oldParent.equals(newParent))) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("no parent change: wbs not affected"); } return; } Integer projectID = workItemBean.getProjectID(); if (projectID == null) { LOGGER.warn("No project found for workItem" + workItemBean.getObjectID()); return; } //old parent workItem and project TWorkItemBean oldParentWorkItemBean = null; boolean sameProjectAsOldParent = false; if (oldParent != null) { try { oldParentWorkItemBean = loadByPrimaryKey(oldParent); Integer oldParentProjectID = oldParentWorkItemBean.getProjectID(); if (oldParentProjectID == null) { LOGGER.warn("No project found for oldParent " + oldParent); return; } else { sameProjectAsOldParent = projectID.equals(oldParentProjectID); } } catch (ItemLoaderException e1) { LOGGER.warn("The oldParent workItem " + oldParent + " does not exist"); return; } } else { //previously it has no parent: the projects are considered the same sameProjectAsOldParent = true; } //new parent workItem and project TWorkItemBean newParentWorkItemBean = null; boolean sameProjectAsNewParent = false; if (newParent != null) { try { newParentWorkItemBean = loadByPrimaryKey(newParent); Integer newParentProjectID = newParentWorkItemBean.getProjectID(); if (newParentProjectID == null) { LOGGER.warn("No project found for newParent " + newParent); return; } else { sameProjectAsNewParent = projectID.equals(newParentProjectID); } } catch (ItemLoaderException e1) { LOGGER.warn("The newParent workItem " + newParent + " does not exist"); return; } } else { //the parent is removed: the projects are considered the same sameProjectAsNewParent = true; } boolean outdent = false; if (contextInformation != null && contextInformation.get(TWorkItemBean.OUTDENT) != null && ((Boolean) contextInformation.get(TWorkItemBean.OUTDENT)).booleanValue()) { outdent = true; } Integer originalWBS = workItemBean.getWBSOnLevel(); if (originalWBS == null) { //renumber if null and get the WBS number again setWbs(projectID); try { //load them again this time with wbs numbers set workItemBean = loadByPrimaryKey(workItemBean.getObjectID()); originalWBS = workItemBean.getWBSOnLevel(); } catch (ItemLoaderException e) { } } //1. remove the item from the original parent's childen and shift the following items up if (sameProjectAsOldParent && !outdent) { //if there were no previous wbs or the project of the workItem differs form the //oldParent's project then there is no need to change anything in the old branch //move the issue's next siblings up one level if it is no outdent //(by outdent the issue's next siblings will be children of the issue) shiftBranch(originalWBS, oldParent, projectID, false); } //2. add the item as last child of the new parent if (sameProjectAsNewParent) { //if the new parent differs from the workItem's parent then no change in wbs Integer newWBS; if (outdent && (contextInformation != null) && (oldParentWorkItemBean != null)) { List<Integer> filteredNextSiblingIDs = (List<Integer>) contextInformation .get(TWorkItemBean.NEXT_SIBLINGS); //by outdent the oldParent becomes the new previous sibling: make space for the outdented item, //by shifting down the siblings of newParent (previous grandparent) after the oldParent Integer oldParentWBS = oldParentWorkItemBean.getWBSOnLevel(); if (oldParentWBS == null) { newWBS = Integer.valueOf(1); } else { newWBS = Integer.valueOf(oldParentWBS.intValue() + 1); } //shift down the children of the newParent beginning with //oldParentWBS exclusive to make place for the outdented issue shiftBranch(oldParentWBS, newParent, projectID, true); //get the next available WBS after the outdented issue's original children Integer nextWbsOnOudentedChildren = getNextWbsOnLevel(workItemBean.getObjectID(), projectID); //gather the all siblings (not just the next ones according to wbs) of the outdented issue, //because it is not guaranteed that at the moment of the outline the sortOrder is by wbs //(can be that in the ReportBeans there is a next sibling which has a lower wbs nummer as the outlined one still according //to the selected ReportBeans sortorder it is a next sibling, consequently it will become a child of outlined issue) Criteria criteria = new Criteria(); criteria.add(SUPERIORWORKITEM, oldParent); criteria.add(WORKITEMKEY, workItemBean.getObjectID(), Criteria.NOT_EQUAL); //criteria.add(WBSONLEVEL, originalWBS, Criteria.GREATER_THAN); criteria.add(PROJECTKEY, projectID); //in the case that the wbs got corrupted but still a wbs existed before try to preserve the order criteria.addAscendingOrderByColumn(WBSONLEVEL); //if wbs does not exist then fall back to workItemKey as wbs criteria.addAscendingOrderByColumn(WORKITEMKEY); List<TWorkItemBean> allSiblingWorkItemBeans = null; try { allSiblingWorkItemBeans = convertTorqueListToBeanList(doSelect(criteria)); } catch (TorqueException e) { LOGGER.warn("Getting the next siblings of the outdented issue " + workItemBean.getObjectID() + failedWith + e.getMessage(), e); } List<String> idChunks = GeneralUtils.getCommaSepararedIDChunksInParenthesis(filteredNextSiblingIDs); //set all next siblings as children of the outdented workItem (see MS Project) //actualize the WBS for old next present siblings (future children of the outdented issue). //No common update is possible because the WBS of the next present siblings might contain gaps Map<Integer, TWorkItemBean> siblingWorkItemsMap = GeneralUtils .createMapFromList(allSiblingWorkItemBeans); for (int i = 0; i < filteredNextSiblingIDs.size(); i++) { //the order from the ReportBeans should be preserved, insependently of current wbs //(consquently the relative wbs order between the siblings might change) TWorkItemBean nextSiblingworkItemBean = siblingWorkItemsMap.get(filteredNextSiblingIDs.get(i)); if (nextSiblingworkItemBean != null && nextSiblingworkItemBean.getWBSOnLevel() != (nextWbsOnOudentedChildren + i)) { nextSiblingworkItemBean.setWBSOnLevel(nextWbsOnOudentedChildren + i); try { saveSimple(nextSiblingworkItemBean); } catch (ItemPersisterException e) { LOGGER.warn("Saving the outdented present workitem " + nextSiblingworkItemBean.getObjectID() + failedWith + e.getMessage()); } } } //renumber those next siblings which were not re-parented (those not present in the ReportBeans) //to fill up the gaps leaved by the re-parented present next siblings //no common update is possible because of gaps int i = 0; if (allSiblingWorkItemBeans != null) { for (Iterator<TWorkItemBean> iterator = allSiblingWorkItemBeans.iterator(); iterator .hasNext();) { TWorkItemBean nextSiblingworkItemBean = iterator.next(); if (!filteredNextSiblingIDs.contains(nextSiblingworkItemBean.getObjectID())) { i++; if (nextSiblingworkItemBean.getWBSOnLevel() != i) { nextSiblingworkItemBean.setWBSOnLevel(i); try { saveSimple(nextSiblingworkItemBean); } catch (ItemPersisterException e) { LOGGER.warn("Saving the outdented not present workItem " + nextSiblingworkItemBean.getObjectID() + failedWith + e.getMessage()); } } } } } String parentCriteria = " AND SUPERIORWORKITEM = " + oldParent; String subprojectCriteria = " PROJECTKEY = " + projectID; //set all present next siblings as children of the outdented workItem (see MS Project). for (Iterator<String> iterator = idChunks.iterator(); iterator.hasNext();) { String idChunk = iterator.next(); String sqlStmt = "UPDATE TWORKITEM SET SUPERIORWORKITEM = " + workItemBean.getObjectID() + " WHERE " + subprojectCriteria + parentCriteria + " AND WORKITEMKEY IN " + idChunk; executeStatemant(sqlStmt); } } else { newWBS = getNextWbsOnLevel(newParent, projectID); } //shift the entire branch down and set the outdented workitem as first child of his previous parent if (EqualUtils.notEqual(workItemBean.getWBSOnLevel(), newWBS)) { workItemBean.setWBSOnLevel(newWBS); } } } /** * The project was changed: recalculate the WBS * @param workItemBean * @param workItemBeanOriginal */ @Override public void projectChanged(TWorkItemBean workItemBean, TWorkItemBean workItemBeanOriginal) { if (workItemBeanOriginal == null) { //new item return; } Integer oldProjectID = workItemBeanOriginal.getProjectID(); Integer newProjectID = workItemBean.getProjectID(); if (oldProjectID == null || newProjectID == null) { LOGGER.warn("Old project " + oldProjectID + " new project " + newProjectID); return; } //same project -> no wbs change if (oldProjectID.equals(newProjectID)) { LOGGER.debug("No project changed "); return; } TWorkItemBean parentWorkItemBean = null; Integer parentID = workItemBean.getSuperiorworkitem(); Integer parentProjectID = null; if (parentID != null) { try { parentWorkItemBean = loadByPrimaryKey(parentID); } catch (ItemLoaderException e) { LOGGER.warn("The parent workItem " + parentID + " does not exist"); } if (parentWorkItemBean != null) { parentProjectID = parentWorkItemBean.getProjectID(); } } Integer originalWBS = workItemBean.getWBSOnLevel(); if (originalWBS == null) { //renumber if null and get the WBS number again setWbs(oldProjectID); try { //load them again this time with wbs numbers set workItemBean = loadByPrimaryKey(workItemBean.getObjectID()); originalWBS = workItemBean.getWBSOnLevel(); } catch (ItemLoaderException e) { } } //1. remove the item from the original parent's childen and shift the following items up //if the item has no parent or the item's parent project and the item's old project is the same if (parentProjectID == null || parentProjectID.equals(oldProjectID)) { //if there were no previous wbs or the project of the workItem differs form the //oldParent's project then there is no need to change anything in the old branch //String commaSeparatedSubprojects = getCommaSepararedSubprojectIDs(oldProjectID, new HashSet<Integer>()); shiftBranch(originalWBS, parentID, oldProjectID, false); } else { LOGGER.debug( "The originalSortOrder was null. There is no need to shift the children of the old parent "); } //2. add the item as last child of the new (parent project) if (parentProjectID == null || parentProjectID.equals(newProjectID)) { //if the new project differs from the workItem's parent then no change in wbs Integer newWbs = getNextWbsOnLevel(parentID, newProjectID); if (EqualUtils.notEqual(workItemBean.getWBSOnLevel(), newWbs)) { workItemBean.setWBSOnLevel(newWbs); } } Integer idNumber = calculateIDNumber(newProjectID, null); if (idNumber != null) { workItemBean.setIDNumber(idNumber); } } /** * Gets the root items or children of a parent from a project * The archived/deleted items are also included * @param parentID * @param projectID * @return */ private static Integer getNextWbsOnLevel(Integer parentID, Integer projectID) { Criteria crit = new Criteria(); if (parentID == null) { crit.add(SUPERIORWORKITEM, (Integer) null, Criteria.ISNULL); } else { crit.add(SUPERIORWORKITEM, parentID, Criteria.EQUAL); } crit.add(PROJECTKEY, projectID); String max = "max(" + WBSONLEVEL + ")"; crit.addSelectColumn(max); Integer maxWBSOnLevel = null; try { maxWBSOnLevel = ((Record) doSelectVillageRecords(crit).get(0)).getValue(1).asIntegerObj(); } catch (Exception e) { LOGGER.error("Getting the maximal wbs for parent " + parentID + " projectID " + projectID + failedWith + e.getMessage()); } if (maxWBSOnLevel == null) { return Integer.valueOf(1); } else { return Integer.valueOf(maxWBSOnLevel.intValue() + 1); } } private static void shiftBranch(Integer originalWBS, Integer parentID, Integer projectID, boolean increase) { String oldParentCriteria = ""; if (parentID != null) { oldParentCriteria = " AND SUPERIORWORKITEM = " + parentID; } else { oldParentCriteria = " AND SUPERIORWORKITEM IS NULL "; } String increaseCriteria; if (increase) { increaseCriteria = "+1 "; } else { increaseCriteria = "-1 "; } String shiftOldParentsChildren = " AND WBSONLEVEL > " + originalWBS; String projectCriteria = " PROJECTKEY = " + projectID; String sqlStmt = "UPDATE TWORKITEM SET WBSONLEVEL = WBSONLEVEL " + increaseCriteria + " WHERE " + projectCriteria + oldParentCriteria + shiftOldParentsChildren; executeStatemant(sqlStmt); } private static void executeStatemant(String sqlStmt) { Connection db = null; try { db = Torque.getConnection(DATABASE_NAME); // it's the same name for all tables here, so we don't care Statement stmt; stmt = db.createStatement(); stmt.executeUpdate(sqlStmt); } catch (TorqueException e) { LOGGER.debug(ExceptionUtils.getStackTrace(e)); } catch (SQLException e) { LOGGER.debug(ExceptionUtils.getStackTrace(e)); } finally { Torque.closeConnection(db); } } /** * Gets the root items or children of a parent from a project * The archived/deleted items are also included * @param parentID * @param projectID * @return */ private static Integer getNextItemID(Integer projectID) { Criteria crit = new Criteria(); crit.add(PROJECTKEY, projectID); String max = "max(" + IDNUMBER + ")"; crit.addSelectColumn(max); Integer maxIDNumber = null; try { List<Record> records = doSelectVillageRecords(crit); if (records != null && !records.isEmpty()) { maxIDNumber = records.get(0).getValue(1).asIntegerObj(); } } catch (Exception e) { LOGGER.error("Getting the maximal IDNumber for projectID " + projectID + failedWith + e.getMessage()); } if (maxIDNumber == null) { return Integer.valueOf(1); } else { return Integer.valueOf(maxIDNumber.intValue() + 1); } } /** * Gets the items from the context in a certain status which were not modified after lastModified * @param workflowContext * @param statusID * @param lastModified * @return */ @Override public List<TWorkItemBean> getInStatusUnmodifiedAfter(WorkflowContext workflowContext, Integer statusID, Date lastModified) { Criteria crit = new Criteria(); CriteriaUtil.addActiveInactiveProjectCriteria(crit); CriteriaUtil.addArchivedDeletedFilter(crit); CriteriaUtil.addAccessLevelPublicFilter(crit); addWorkflowContextCriteria(crit, workflowContext); crit.add(STATE, statusID); crit.add(LASTEDIT, lastModified, Criteria.LESS_EQUAL); try { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Criteria " + crit); } return convertTorqueListToBeanList(doSelect(crit)); } catch (TorqueException e) { LOGGER.error("Loading the items in status " + statusID + " not modifed after " + lastModified + failedWith + e.getMessage()); return new ArrayList<TWorkItemBean>(); } } /** * Gets the itemIDs from the context in a certain status without a status change after lastModified * @param workflowContext * @param statusID * @param lastModified * @return */ @Override public List<Integer> getInStatusNoStatusChangeAfter(WorkflowContext workflowContext, Integer statusID, Date lastModified) { List<Integer> itemIDs = null; Criteria crit = new Criteria(); String maxLastEdit = "MAX(" + THistoryTransactionPeer.LASTEDIT + ")"; CriteriaUtil.addActiveInactiveProjectCriteria(crit); CriteriaUtil.addArchivedDeletedFilter(crit); CriteriaUtil.addAccessLevelPublicFilter(crit); addWorkflowContextCriteria(crit, workflowContext); crit.add(STATE, statusID); crit.addJoin(WORKITEMKEY, THistoryTransactionPeer.WORKITEM); crit.addJoin(THistoryTransactionPeer.OBJECTID, TFieldChangePeer.HISTORYTRANSACTION); crit.add(TFieldChangePeer.FIELDKEY, SystemFields.INTEGER_STATE); crit.addSelectColumn(THistoryTransactionPeer.WORKITEM); crit.addGroupByColumn(THistoryTransactionPeer.WORKITEM); Criterion criterion = crit.getNewCriterion(maxLastEdit, lastModified, Criteria.LESS_EQUAL); crit.addHaving(criterion); List<Record> records = new LinkedList<Record>(); try { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Criteria " + crit); } records = doSelectVillageRecords(crit); } catch (Exception e) { LOGGER.error("Groupping the workitems by date of the last modified status before " + lastModified + failedWith + e.getMessage()); } try { if (records != null && !records.isEmpty()) { itemIDs = new ArrayList<Integer>(records.size()); for (Record record : records) { Integer itemID = record.getValue(1).asIntegerObj(); itemIDs.add(itemID); } } } catch (Exception e) { LOGGER.error("Loading the items in status " + statusID + " not modifed after " + lastModified + failedWith + e.getMessage()); } return itemIDs; } public List<IntegerStringBean> getPath(Integer objectID) throws ItemLoaderException { List<IntegerStringBean> result = new ArrayList<IntegerStringBean>(); Integer workItemID = objectID; while (workItemID != null) { TWorkItem tWorkItem = getInternalWorkItem(workItemID); result.add(0, new IntegerStringBean(tWorkItem.getSynopsis(), tWorkItem.getObjectID())); workItemID = tWorkItem.getSuperiorworkitem(); } return result; } private TWorkItem getInternalWorkItem(Integer objectID) throws ItemLoaderException { TWorkItem tWorkItem = null; try { tWorkItem = retrieveByPK(objectID); } catch (Exception e) { LOGGER.info("Loading the workItem by primary key " + objectID + failedWith + e.getMessage()); LOGGER.debug(ExceptionUtils.getStackTrace(e)); throw new ItemLoaderException("Loading the workItem by " + objectID + " failed", e); } if (tWorkItem == null) { throw new ItemLoaderException("No item found for workItem ID " + objectID); } return tWorkItem; } /** * Filter the items by context * @param crit * @param workflowContext * @return */ private static Criteria addWorkflowContextCriteria(Criteria crit, WorkflowContext workflowContext) { Integer itemTypeID = workflowContext.getItemTypeID(); Integer projectTypeID = workflowContext.getProjectTypeID(); Integer projectID = workflowContext.getProjectID(); if (itemTypeID != null) { crit.add(CATEGORYKEY, itemTypeID); } if (projectTypeID != null) { crit.addJoin(PROJECTKEY, TProjectPeer.PKEY); crit.add(TProjectPeer.PROJECTTYPE, projectTypeID); } else { if (projectID != null) { crit.add(PROJECTKEY, projectID); } } return crit; } }