| /********************************************************************* |
| * Copyright (c) 2014 Boeing |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Boeing - initial API and implementation |
| **********************************************************************/ |
| |
| package org.eclipse.osee.ats.core.action; |
| |
| import com.fasterxml.jackson.core.JsonFactory; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map.Entry; |
| import org.eclipse.osee.ats.api.AtsApi; |
| import org.eclipse.osee.ats.api.IAtsObject; |
| import org.eclipse.osee.ats.api.IAtsWorkItem; |
| import org.eclipse.osee.ats.api.agile.IAgileBacklog; |
| import org.eclipse.osee.ats.api.agile.IAgileFeatureGroup; |
| import org.eclipse.osee.ats.api.agile.IAgileSprint; |
| import org.eclipse.osee.ats.api.agile.IAgileTeam; |
| import org.eclipse.osee.ats.api.ai.IAtsActionableItem; |
| import org.eclipse.osee.ats.api.data.AtsArtifactTypes; |
| import org.eclipse.osee.ats.api.data.AtsAttributeTypes; |
| import org.eclipse.osee.ats.api.data.AtsRelationTypes; |
| import org.eclipse.osee.ats.api.ev.IAtsWorkPackage; |
| import org.eclipse.osee.ats.api.notify.AtsNotificationEventFactory; |
| import org.eclipse.osee.ats.api.notify.AtsNotifyType; |
| import org.eclipse.osee.ats.api.team.ChangeTypes; |
| import org.eclipse.osee.ats.api.team.CreateTeamOption; |
| import org.eclipse.osee.ats.api.team.IAtsTeamDefinition; |
| import org.eclipse.osee.ats.api.user.AtsCoreUsers; |
| import org.eclipse.osee.ats.api.user.AtsUser; |
| import org.eclipse.osee.ats.api.util.IAtsChangeSet; |
| import org.eclipse.osee.ats.api.workdef.AtsWorkDefinitionToken; |
| import org.eclipse.osee.ats.api.workdef.AtsWorkDefinitionTokens; |
| import org.eclipse.osee.ats.api.workdef.IRelationResolver; |
| import org.eclipse.osee.ats.api.workdef.model.StateDefinition; |
| import org.eclipse.osee.ats.api.workdef.model.WorkDefinition; |
| import org.eclipse.osee.ats.api.workflow.ActionResult; |
| import org.eclipse.osee.ats.api.workflow.IAtsAction; |
| import org.eclipse.osee.ats.api.workflow.IAtsActionService; |
| import org.eclipse.osee.ats.api.workflow.IAtsGoal; |
| import org.eclipse.osee.ats.api.workflow.IAtsTeamWorkflow; |
| import org.eclipse.osee.ats.api.workflow.INewActionListener; |
| import org.eclipse.osee.ats.api.workflow.IWorkItemListener; |
| import org.eclipse.osee.ats.api.workflow.NewActionData; |
| import org.eclipse.osee.ats.api.workflow.log.LogType; |
| import org.eclipse.osee.ats.core.internal.util.AtsIdProvider; |
| import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; |
| import org.eclipse.osee.framework.core.data.ArtifactId; |
| import org.eclipse.osee.framework.core.data.ArtifactToken; |
| import org.eclipse.osee.framework.core.data.ArtifactTypeToken; |
| import org.eclipse.osee.framework.core.data.AttributeTypeToken; |
| import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; |
| import org.eclipse.osee.framework.core.util.JsonUtil; |
| import org.eclipse.osee.framework.jdk.core.type.OseeArgumentException; |
| import org.eclipse.osee.framework.jdk.core.type.OseeCoreException; |
| import org.eclipse.osee.framework.jdk.core.type.OseeStateException; |
| import org.eclipse.osee.framework.jdk.core.util.Conditions; |
| import org.eclipse.osee.framework.jdk.core.util.DateUtil; |
| import org.eclipse.osee.framework.jdk.core.util.Lib; |
| import org.eclipse.osee.framework.jdk.core.util.Strings; |
| |
| /** |
| * @author Donald G. Dunne |
| */ |
| public class AtsActionService implements IAtsActionService { |
| private final AtsApi atsApi; |
| |
| private IAtsTeamDefinition topTeamDefinition; |
| private JsonFactory jsonFactory; |
| private IWorkItemListener workItemListener; |
| private static final Collection<INewActionListener> actionListeners = new ArrayList<>(); |
| |
| public AtsActionService() { |
| this(null); |
| // for jax-rs |
| } |
| |
| public AtsActionService(AtsApi atsApi) { |
| this.atsApi = atsApi; |
| } |
| |
| @Override |
| public ActionResult createAction(NewActionData data, IAtsChangeSet changes) { |
| ActionResult result = null; |
| try { |
| AtsUser asUser = atsApi.getUserService().getUserByUserId(data.getAsUserId()); |
| Conditions.assertNotNull(asUser, "As-User must be specified."); |
| AtsUser createdBy = null; |
| if (Strings.isValid(data.getCreatedByUserId())) { |
| createdBy = atsApi.getUserService().getUserByUserId(data.getCreatedByUserId()); |
| } |
| if (createdBy == null && Strings.isValid(data.getCreatedByUserId())) { |
| createdBy = atsApi.getUserService().getUserByUserId(data.getCreatedByUserId()); |
| } |
| Conditions.assertNotNull(createdBy, "Created-By must be specified."); |
| Conditions.assertNotNullOrEmpty(data.getAiIds(), "Actionable Items must be specified"); |
| List<IAtsActionableItem> ais = new LinkedList<>(); |
| for (String aiId : data.getAiIds()) { |
| IAtsActionableItem ai = atsApi.getQueryService().getConfigItem(Long.valueOf(aiId)); |
| Conditions.assertNotNull(ai, "Actionable Item must be specified."); |
| ais.add(ai); |
| } |
| |
| Date needByDate = null; |
| if (Strings.isNumeric(data.getNeedByDateLong())) { |
| needByDate = new Date(Long.valueOf(data.getNeedByDateLong())); |
| } else if (Strings.isValid(data.getNeedByDate())) { |
| try { |
| needByDate = DateUtil.getDate("yyyy-MM-dd", data.getNeedByDate()); |
| } catch (Exception ex) { |
| throw new OseeCoreException("Error parsing date. Must be mm/dd/yyyy.", ex); |
| } |
| } |
| Date createdDate = null; |
| if (Strings.isNumeric(data.getCreatedDateLong())) { |
| createdDate = new Date(Long.valueOf(data.getCreatedDateLong())); |
| } else { |
| createdDate = new Date(); |
| } |
| result = createAction(asUser, data.getTitle(), data.getDescription(), data.getChangeType(), data.getPriority(), |
| data.isValidationRequired(), needByDate, ais, createdDate, createdBy, java.util.Collections.emptyList(), |
| changes); |
| |
| if (result.getResults().isErrors()) { |
| return result; |
| } |
| |
| if (Strings.isValid(data.getPoints())) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| IAgileTeam agileTeam = null; |
| if (Strings.isNumeric(data.getAgileTeam())) { |
| agileTeam = atsApi.getQueryService().getConfigItem(ArtifactId.valueOf(data.getAgileTeam())); |
| } |
| if (agileTeam == null) { |
| IAtsTeamDefinition teamDef = teamWf.getTeamDefinition(); |
| agileTeam = atsApi.getAgileService().getAgileTeam(teamDef); |
| } |
| String pointsAttrType = atsApi.getAttributeResolver().getSoleAttributeValue(agileTeam, |
| AtsAttributeTypes.PointsAttributeType, null); |
| if (Strings.isInValid(pointsAttrType)) { |
| pointsAttrType = atsApi.getAttributeResolver().getSoleAttributeValue(teamWf.getTeamDefinition(), |
| AtsAttributeTypes.PointsAttributeType, null); |
| } |
| if (!Strings.isValid(pointsAttrType)) { |
| throw new OseeArgumentException( |
| "Points Attribute Type must be specified on either Agile Team or Team Defintion to set Points", |
| agileTeam.toStringWithId()); |
| } |
| AttributeTypeToken attributeType = atsApi.tokenService().getAttributeType(pointsAttrType); |
| |
| changes.setSoleAttributeValue(teamWf, attributeType, data.getPoints()); |
| } |
| } |
| |
| if (data.isUnplanned()) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| changes.setSoleAttributeValue(teamWf, AtsAttributeTypes.UnplannedWork, true); |
| } |
| } |
| |
| String featureGroup = data.getFeatureGroup(); |
| if (Strings.isValid(featureGroup)) { |
| IAgileFeatureGroup group = null; |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| if (Strings.isNumeric(featureGroup)) { |
| group = atsApi.getAgileService().getAgileFeatureGroup(ArtifactId.valueOf(featureGroup)); |
| } else { |
| IAgileTeam aTeam = atsApi.getAgileService().getAgileTeam(teamWf.getTeamDefinition()); |
| if (aTeam != null) { |
| for (IAgileFeatureGroup grp : atsApi.getAgileService().getAgileFeatureGroups(aTeam)) { |
| if (grp.getName().equals(featureGroup)) { |
| group = grp; |
| break; |
| } |
| } |
| } |
| } |
| if (group != null) { |
| changes.relate(teamWf, AtsRelationTypes.AgileFeatureToItem_AgileFeatureGroup, group); |
| } |
| } |
| } |
| |
| // Set sprint |
| String sprintStr = data.getSprint(); |
| if (Strings.isValid(sprintStr)) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| IAgileSprint sprint = null; |
| if (Strings.isNumeric(sprintStr)) { |
| sprint = atsApi.getAgileService().getAgileSprint(Long.valueOf(sprintStr)); |
| } else { |
| IAgileTeam aTeam = atsApi.getAgileService().getAgileTeam(sprint); |
| for (IAgileSprint aSprint : atsApi.getAgileService().getAgileSprints(aTeam)) { |
| if (aSprint.getName().equals(sprintStr)) { |
| sprint = aSprint; |
| break; |
| } |
| } |
| } |
| if (sprint != null) { |
| changes.relate(sprint, AtsRelationTypes.AgileSprintToItem_AtsItem, teamWf); |
| } |
| } |
| } |
| |
| // Set backlog if not already set |
| // NOTE: This may cause a problem if team already configured to add new items to backlog |
| String agileTeamStr = data.getAgileTeam(); |
| if (Strings.isValid(agileTeamStr)) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| IAgileTeam aTeam = null; |
| if (Strings.isNumeric(agileTeamStr)) { |
| aTeam = atsApi.getAgileService().getAgileTeam(Long.valueOf(agileTeamStr)); |
| } else { |
| ArtifactId aTeamArt = |
| atsApi.getQueryService().getArtifactByNameOrSentinel(AtsArtifactTypes.AgileTeam, agileTeamStr); |
| if (aTeamArt.isValid()) { |
| aTeam = atsApi.getAgileService().getAgileTeam(aTeamArt); |
| } |
| } |
| if (aTeam != null) { |
| IAgileBacklog backlog = atsApi.getAgileService().getBacklogForTeam(aTeam.getId()); |
| if (backlog != null) { |
| if (!atsApi.getRelationResolver().areRelated(backlog, AtsRelationTypes.Goal_Member, teamWf)) { |
| changes.relate(backlog, AtsRelationTypes.Goal_Member, teamWf); |
| } |
| } |
| } |
| } |
| } |
| |
| // set originator |
| if (Strings.isNumeric(data.getOriginatorStr())) { |
| AtsUser originator = atsApi.getUserService().getUserById(ArtifactId.valueOf(data.getOriginatorStr())); |
| if (originator != null) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| changes.setSoleAttributeValue(teamWf, AtsAttributeTypes.CreatedBy, originator.getUserId()); |
| } |
| } |
| } |
| |
| // set assignee |
| if (Strings.isValid(data.getAssigneeStr())) { |
| List<AtsUser> assignees = new LinkedList<>(); |
| for (String id : data.getAssigneeStr().split(",")) { |
| AtsUser user = atsApi.getUserService().getUserById(ArtifactId.valueOf(id)); |
| if (user != null) { |
| assignees.add(user); |
| } |
| } |
| if (!assignees.isEmpty()) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| changes.setAssignees(teamWf, assignees); |
| } |
| } |
| } |
| |
| // set work package |
| if (Strings.isValid(data.getWorkPackage())) { |
| IAtsWorkPackage workPkg = null; |
| if (Strings.isNumeric(data.getWorkPackage())) { |
| workPkg = atsApi.getEarnedValueService().getWorkPackage(ArtifactId.valueOf(data.getWorkPackage())); |
| } else { |
| ArtifactId art = atsApi.getQueryService().getArtifactByNameOrSentinel(AtsArtifactTypes.WorkPackage, |
| data.getWorkPackage()); |
| if (art.isValid()) { |
| workPkg = atsApi.getEarnedValueService().getWorkPackage(art); |
| } |
| } |
| if (workPkg != null) { |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| atsApi.getEarnedValueService().setWorkPackage(workPkg, teamWf, changes); |
| } |
| } else { |
| result.getResults().errorf("Inavlid Work Package id or name [%s]", data.getWorkPackage()); |
| } |
| } |
| |
| // set any additional values |
| for (Entry<String, String> attr : data.getAttrValues().entrySet()) { |
| if (!Strings.isNumeric(attr.getKey())) { |
| throw new OseeArgumentException("Invalid attribute type id %s", attr.getKey()); |
| } |
| AttributeTypeToken attributeType = atsApi.tokenService().getAttributeType(Long.valueOf(attr.getKey())); |
| if (attributeType == null) { |
| throw new OseeArgumentException("Invalid attribute type id %s", attr.getKey()); |
| } |
| for (IAtsTeamWorkflow teamWf : result.getTeamWfs()) { |
| changes.setSoleAttributeValue(teamWf, attributeType, attr.getValue()); |
| } |
| } |
| } catch (Exception ex) { |
| result = new ActionResult(null, null); |
| result.getResults().errorf("Exception creating Action %s", Lib.exceptionToString(ex)); |
| } |
| return result; |
| } |
| |
| @Override |
| public ActionResult createAction(AtsUser user, String title, String desc, ChangeTypes changeType, String priority, |
| boolean validationRequired, Date needByDate, Collection<IAtsActionableItem> actionableItems, Date createdDate, |
| AtsUser createdBy, Collection<INewActionListener> newActionListeners, IAtsChangeSet changes) { |
| ActionResult result = null; |
| try { |
| Conditions.checkNotNullOrEmptyOrContainNull(actionableItems, "actionableItems"); |
| Conditions.assertNotNullOrEmpty(title, "Title must be specified"); |
| |
| /** |
| * if "tt" is title, this is an action created for development. To make it easier, all fields are automatically |
| * filled in for ATS developer |
| */ |
| IAtsAction action = createAction(title, desc, changeType, priority, validationRequired, needByDate, changes); |
| |
| // Retrieve Team Definitions corresponding to selected Actionable Items |
| Collection<IAtsTeamDefinition> teamDefs = |
| atsApi.getTeamDefinitionService().getImpactedTeamDefs(actionableItems); |
| if (teamDefs.isEmpty()) { |
| StringBuffer sb = new StringBuffer("No teams returned for Action's selected Actionable Items\n"); |
| for (IAtsActionableItem aia : actionableItems) { |
| sb.append("Selected AI \"" + aia + "\" " + aia.getIdString() + "\n"); |
| } |
| throw new OseeStateException(sb.toString()); |
| } |
| |
| // Create team workflow artifacts |
| List<IAtsTeamWorkflow> teamWfs = new ArrayList<>(); |
| for (IAtsTeamDefinition teamDef : teamDefs) { |
| List<AtsUser> leads = |
| new LinkedList<>(atsApi.getTeamDefinitionService().getLeads(teamDef, actionableItems)); |
| if (leads.isEmpty()) { |
| leads.add(AtsCoreUsers.UNASSIGNED_USER); |
| } |
| IAtsTeamWorkflow teamWf = createTeamWorkflow(action, teamDef, actionableItems, leads, changes, createdDate, |
| createdBy, newActionListeners); |
| teamWfs.add(teamWf); |
| changes.add(teamWf); |
| } |
| |
| // Notify listener of action creation |
| if (newActionListeners != null) { |
| for (INewActionListener listener : newActionListeners) { |
| listener.actionCreated(action); |
| } |
| } |
| |
| changes.add(action); |
| result = new ActionResult(action, teamWfs); |
| } catch (Exception ex) { |
| result = new ActionResult(null, null); |
| result.getResults().errorf("Exception creating Action %s", Lib.exceptionToString(ex)); |
| } |
| return result; |
| } |
| |
| @Override |
| public IAtsAction createAction(String title, String desc, ChangeTypes changeType, String priority, |
| boolean validationRequired, Date needByDate, IAtsChangeSet changes) { |
| ArtifactToken actionArt = changes.createArtifact(AtsArtifactTypes.Action, title); |
| IAtsAction action = atsApi.getWorkItemService().getAction(actionArt); |
| IAtsTeamDefinition topTeamDefinition = getTopTeamDef(); |
| atsApi.getActionService().setAtsId(action, topTeamDefinition, workItemListener, changes); |
| changes.add(action); |
| setArtifactIdentifyData(action, title, desc, changeType, priority, validationRequired, needByDate, changes); |
| return action; |
| } |
| |
| private IAtsTeamDefinition getTopTeamDef() { |
| if (topTeamDefinition == null) { |
| topTeamDefinition = atsApi.getTeamDefinitionService().getTopTeamDefinition(); |
| } |
| return topTeamDefinition; |
| } |
| |
| @Override |
| public IAtsTeamWorkflow createTeamWorkflow(IAtsAction action, IAtsTeamDefinition teamDef, |
| Collection<IAtsActionableItem> actionableItems, Collection<AtsUser> assignees, IAtsChangeSet changes, |
| Date createdDate, AtsUser createdBy, Collection<INewActionListener> newActionListeners, |
| CreateTeamOption... createTeamOption) { |
| Conditions.assertNotNull(teamDef, "Team Definition can not be null"); |
| WorkDefinition workDef = |
| atsApi.getWorkDefinitionService().computeWorkDefinitionForTeamWfNotYetCreated(teamDef, newActionListeners); |
| Conditions.assertNotNull(workDef, "Work Definition can not be null"); |
| |
| /** |
| * Get Team Workflow artifact type from listeners, else from Work Def, else from Team Def |
| */ |
| ArtifactTypeToken teamWorkflowArtifactType = null; |
| if (newActionListeners != null) { |
| for (INewActionListener listener : newActionListeners) { |
| ArtifactTypeToken artType = listener.getOverrideArtifactType(teamDef); |
| if (artType.isValid()) { |
| if (teamWorkflowArtifactType != null) { |
| throw new OseeArgumentException("Provided listeners can not provide override art type"); |
| } |
| teamWorkflowArtifactType = artType; |
| } |
| } |
| } |
| if (teamWorkflowArtifactType == null) { |
| teamWorkflowArtifactType = workDef != null ? workDef.getArtType() : null; |
| } |
| if (teamWorkflowArtifactType == null) { |
| teamWorkflowArtifactType = getTeamWorkflowArtifactType(teamDef); |
| } |
| Conditions.assertNotNull(teamWorkflowArtifactType, "Team Workflow Artifact Type can not be null"); |
| |
| // NOTE: The persist of the workflow will auto-email the assignees |
| IAtsTeamWorkflow teamWf = createTeamWorkflow(action, teamDef, actionableItems, assignees, createdDate, createdBy, |
| teamWorkflowArtifactType, newActionListeners, changes, createTeamOption); |
| return teamWf; |
| } |
| |
| public ArtifactTypeToken getTeamWorkflowArtifactType(IAtsTeamDefinition teamDef) { |
| return getTeamWorkflowArtifactType(teamDef, atsApi); |
| } |
| |
| public static ArtifactTypeToken getTeamWorkflowArtifactType(IAtsTeamDefinition teamDef, AtsApi atsApi) { |
| Conditions.checkNotNull(teamDef, "teamDef"); |
| ArtifactTypeToken teamWorkflowArtifactType = AtsArtifactTypes.TeamWorkflow; |
| if (teamDef.getStoreObject() != null) { |
| String artifactTypeName = atsApi.getAttributeResolver().getSoleAttributeValue(teamDef, |
| AtsAttributeTypes.TeamWorkflowArtifactType, null); |
| if (Strings.isValid(artifactTypeName)) { |
| boolean found = false; |
| for (ArtifactTypeToken type : atsApi.getArtifactTypes()) { |
| if (type.getName().equals(artifactTypeName)) { |
| teamWorkflowArtifactType = type; |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| throw new OseeArgumentException( |
| "Team Workflow Artifact Type name [%s] off Team Definition %s could not be found.", artifactTypeName, |
| teamDef.toStringWithId()); |
| } |
| } |
| } |
| return teamWorkflowArtifactType; |
| } |
| |
| @Override |
| public IAtsTeamWorkflow createTeamWorkflow(IAtsAction action, IAtsTeamDefinition teamDef, |
| Collection<IAtsActionableItem> actionableItems, Collection<AtsUser> assignees, Date createdDate, |
| AtsUser createdBy, ArtifactTypeToken artifactType, Collection<INewActionListener> newActionListeners, |
| IAtsChangeSet changes, CreateTeamOption... createTeamOption) { |
| |
| WorkDefinition workDef = null; |
| if (newActionListeners != null && !newActionListeners.isEmpty()) { |
| for (INewActionListener actionListener : newActionListeners) { |
| AtsWorkDefinitionToken workDefTok = actionListener.getOverrideWorkDefinitionId(teamDef); |
| if (workDefTok != null) { |
| workDef = atsApi.getWorkDefinitionService().getWorkDefinition(workDefTok); |
| } |
| } |
| } |
| // Determine of any osgi registered listeners want to provide work def |
| if (workDef == null && actionListeners != null) { |
| for (INewActionListener listener : actionListeners) { |
| AtsWorkDefinitionToken overrideWorkDefinitionId = listener.getOverrideWorkDefinitionId(teamDef); |
| if (overrideWorkDefinitionId != null) { |
| workDef = atsApi.getWorkDefinitionService().getWorkDefinition(overrideWorkDefinitionId); |
| break; |
| } |
| } |
| } |
| // Else, use normal computed work def |
| if (workDef == null) { |
| workDef = |
| atsApi.getWorkDefinitionService().computeWorkDefinitionForTeamWfNotYetCreated(teamDef, newActionListeners); |
| } |
| Conditions.assertNotNull(workDef, "Work Definition can no be null"); |
| |
| if (!Arrays.asList(createTeamOption).contains(CreateTeamOption.Duplicate_If_Exists)) { |
| // Make sure team doesn't already exist |
| for (IAtsTeamWorkflow teamArt : action.getTeamWorkflows()) { |
| if (teamArt.getTeamDefinition().equals(teamDef)) { |
| throw new OseeArgumentException("Team [%s] already exists for Action [%s]", teamDef, |
| atsApi.getAtsId(action)); |
| } |
| } |
| } |
| |
| List<IAtsActionableItem> applicableAis = new LinkedList<>(); |
| for (IAtsActionableItem ai : actionableItems) { |
| IAtsTeamDefinition teamDefinitionInherited = |
| ai.getAtsApi().getActionableItemService().getTeamDefinitionInherited(ai); |
| if (teamDefinitionInherited != null && teamDef.getId().equals(teamDefinitionInherited.getId())) { |
| applicableAis.add(ai); |
| } |
| } |
| |
| IAtsTeamWorkflow teamWf = null; |
| ArtifactToken artToken = null; |
| if (newActionListeners != null) { |
| for (INewActionListener listener : newActionListeners) { |
| artToken = listener.getArtifactToken(applicableAis); |
| } |
| } |
| |
| if (artToken == null) { |
| teamWf = atsApi.getWorkItemService().getTeamWf(changes.createArtifact(artifactType, "")); |
| } else { |
| teamWf = atsApi.getWorkItemService().getTeamWf(changes.createArtifact(artToken)); |
| } |
| |
| atsApi.getWorkDefinitionService().setWorkDefinitionAttrs((IAtsWorkItem) teamWf, workDef, changes); |
| setArtifactIdentifyData(action, teamWf, changes); |
| |
| /** |
| * Relate Workflow to ActionableItems (by id) if team is responsible for that AI |
| */ |
| for (IAtsActionableItem aia : applicableAis) { |
| atsApi.getActionableItemService().addActionableItem(teamWf, aia, changes); |
| } |
| |
| // Relate WorkFlow to Team Definition (by id due to relation loading issues) |
| changes.setSoleAttributeValue(teamWf, AtsAttributeTypes.TeamDefinitionReference, teamDef.getStoreObject()); |
| |
| setAtsId(teamWf, teamWf.getTeamDefinition(), workItemListener, changes); |
| |
| // Initialize state machine |
| initializeNewStateMachine(teamWf, assignees, createdDate, createdBy, workDef, changes); |
| |
| // Notify listener of team creation |
| if (newActionListeners != null) { |
| for (INewActionListener listener : newActionListeners) { |
| listener.teamCreated(action, teamWf, changes); |
| } |
| } |
| // Notify any osgi registered listeners |
| if (actionListeners != null) { |
| for (INewActionListener listener : actionListeners) { |
| listener.teamCreated(action, teamWf, changes); |
| } |
| } |
| |
| // Relate Action to WorkFlow |
| changes.relate(action, AtsRelationTypes.ActionToWorkflow_TeamWorkflow, teamWf); |
| |
| // Auto-add actions to configured goals |
| addActionToConfiguredGoal(teamDef, teamWf, actionableItems, null, changes); |
| |
| changes.add(teamWf); |
| |
| changes.addWorkItemNotificationEvent(AtsNotificationEventFactory.getWorkItemNotificationEvent( |
| AtsCoreUsers.SYSTEM_USER, teamWf, AtsNotifyType.SubscribedTeamOrAi)); |
| |
| changes.addWorkflowCreated(teamWf); |
| |
| return teamWf; |
| } |
| |
| @Override |
| public void initializeNewStateMachine(IAtsWorkItem workItem, Collection<AtsUser> assignees, Date createdDate, |
| AtsUser createdBy, WorkDefinition workDefinition, IAtsChangeSet changes) { |
| Conditions.checkNotNull(createdDate, "createdDate"); |
| Conditions.checkNotNull(createdBy, "createdBy"); |
| Conditions.checkNotNull(changes, "changes"); |
| Conditions.checkNotNull(workDefinition, "workDefinition"); |
| |
| // set for bootstrapping issues only when creating initial work item |
| atsApi.getWorkDefinitionService().internalSetWorkDefinition(workItem, workDefinition); |
| |
| StateDefinition startState = workDefinition.getStartState(); |
| changes.initalizeWorkflow(workItem, startState, assignees); |
| |
| AtsUser user = createdBy; |
| setCreatedBy(workItem, user, true, createdDate, changes); |
| TransitionManager.logStateStartedEvent(workItem, startState, createdDate, user); |
| } |
| |
| private void logCreatedByChange(IAtsWorkItem workItem, AtsUser user, Date date, AtsUser asUser) { |
| if (atsApi.getAttributeResolver().getSoleAttributeValue(workItem, AtsAttributeTypes.CreatedBy, null) == null) { |
| workItem.getLog().addLog(LogType.Originated, "", "", date, user.getUserId()); |
| } else { |
| workItem.getLog().addLog(LogType.Originated, "", "Changed by " + asUser.getName(), date, user.getUserId()); |
| } |
| } |
| |
| @Override |
| public void setCreatedBy(IAtsWorkItem workItem, AtsUser user, boolean logChange, Date date, IAtsChangeSet changes) { |
| if (logChange) { |
| logCreatedByChange(workItem, user, date, changes.getAsUser()); |
| } |
| |
| if (atsApi.getAttributeResolver().isAttributeTypeValid(workItem, AtsAttributeTypes.CreatedBy)) { |
| changes.setSoleAttributeValue(workItem, AtsAttributeTypes.CreatedBy, user.getUserId()); |
| } |
| if (atsApi.getAttributeResolver().isAttributeTypeValid(workItem, AtsAttributeTypes.CreatedDate)) { |
| changes.setSoleAttributeValue(workItem, AtsAttributeTypes.CreatedDate, date); |
| } |
| changes.addWorkItemNotificationEvent(AtsNotificationEventFactory.getWorkItemNotificationEvent(changes.getAsUser(), |
| workItem, AtsNotifyType.Originator)); |
| } |
| |
| /** |
| * Auto-add actions to a goal configured with relations to the given ActionableItem or Team Definition |
| */ |
| @Override |
| public void addActionToConfiguredGoal(IAtsTeamDefinition teamDef, IAtsTeamWorkflow teamWf, |
| Collection<IAtsActionableItem> actionableItems, IAtsGoal handledGoal, IAtsChangeSet changes) { |
| // Auto-add this team artifact to configured goals |
| IRelationResolver relationResolver = atsApi.getRelationResolver(); |
| for (IAtsGoal goal : relationResolver.getRelated(teamDef, AtsRelationTypes.AutoAddActionToGoal_Goal, |
| IAtsGoal.class)) { |
| if (goal.equals(handledGoal)) { |
| continue; |
| } |
| if (!relationResolver.areRelated(goal, AtsRelationTypes.Goal_Member, teamWf)) { |
| changes.relate(goal, AtsRelationTypes.Goal_Member, teamWf); |
| changes.add(goal); |
| } |
| } |
| |
| // Auto-add this actionable item to configured goals |
| for (IAtsActionableItem aia : actionableItems) { |
| for (IAtsGoal goal : relationResolver.getRelated(aia, AtsRelationTypes.AutoAddActionToGoal_Goal, |
| IAtsGoal.class)) { |
| if (goal.equals(handledGoal)) { |
| continue; |
| } |
| if (!relationResolver.areRelated(goal, AtsRelationTypes.Goal_Member, teamWf)) { |
| changes.relate(goal, AtsRelationTypes.Goal_Member, teamWf); |
| changes.add(goal); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Set Team Workflow attributes off given action artifact |
| */ |
| public void setArtifactIdentifyData(IAtsAction fromAction, IAtsTeamWorkflow toTeam, IAtsChangeSet changes) { |
| Conditions.checkNotNull(fromAction, "fromAction"); |
| Conditions.checkNotNull(toTeam, "toTeam"); |
| Conditions.checkNotNull(changes, "changes"); |
| ChangeTypes changeType = ChangeTypes.valueOf( |
| atsApi.getAttributeResolver().getSoleAttributeValue(fromAction, AtsAttributeTypes.ChangeType, "None")); |
| setArtifactIdentifyData(toTeam, fromAction.getName(), |
| atsApi.getAttributeResolver().getSoleAttributeValue(fromAction, AtsAttributeTypes.Description, ""), changeType, |
| atsApi.getAttributeResolver().getSoleAttributeValue(fromAction, AtsAttributeTypes.Priority, ""), |
| atsApi.getAttributeResolver().getSoleAttributeValue(fromAction, AtsAttributeTypes.ValidationRequired, false), |
| atsApi.getAttributeResolver().getSoleAttributeValue(fromAction, AtsAttributeTypes.NeedBy, (Date) null), |
| changes); |
| } |
| |
| /** |
| * Since there is no shared attribute yet, action and workflow arts are all populate with identify data |
| */ |
| public void setArtifactIdentifyData(IAtsObject atsObject, String title, String desc, ChangeTypes changeType, |
| String priority, Boolean validationRequired, Date needByDate, IAtsChangeSet changes) { |
| changes.setSoleAttributeValue(atsObject, CoreAttributeTypes.Name, title); |
| if (Strings.isValid(desc)) { |
| changes.addAttribute(atsObject, AtsAttributeTypes.Description, desc); |
| } |
| if (changeType != null) { |
| changes.setSoleAttributeValue(atsObject, AtsAttributeTypes.ChangeType, changeType.name()); |
| } |
| if (Strings.isValid(priority)) { |
| changes.addAttribute(atsObject, AtsAttributeTypes.Priority, priority); |
| } |
| if (needByDate != null) { |
| changes.addAttribute(atsObject, AtsAttributeTypes.NeedBy, needByDate); |
| } |
| if (validationRequired) { |
| changes.addAttribute(atsObject, AtsAttributeTypes.ValidationRequired, true); |
| } |
| } |
| |
| @Override |
| public Collection<IAtsTeamWorkflow> getSiblingTeamWorkflows(IAtsTeamWorkflow teamWf) { |
| List<IAtsTeamWorkflow> teams = new LinkedList<>(); |
| IAtsAction action = getAction(teamWf); |
| for (IAtsTeamWorkflow teamChild : atsApi.getRelationResolver().getRelated(action, |
| AtsRelationTypes.ActionToWorkflow_TeamWorkflow, IAtsTeamWorkflow.class)) { |
| if (teamChild.notEqual(teamWf)) { |
| teams.add(teamChild); |
| } |
| } |
| return teams; |
| } |
| |
| @Override |
| public IAtsAction getAction(IAtsTeamWorkflow teamWf) { |
| return atsApi.getRelationResolver().getRelatedOrNull(teamWf, AtsRelationTypes.ActionToWorkflow_Action, |
| IAtsAction.class); |
| } |
| |
| @Override |
| public void setAtsId(IAtsObject newObject, IAtsTeamDefinition teamDef, IWorkItemListener workItemListener, |
| IAtsChangeSet changes) { |
| AtsIdProvider atsIdProvider = |
| new AtsIdProvider(atsApi.getSequenceProvider(), atsApi.getAttributeResolver(), newObject, teamDef); |
| atsIdProvider.setWorkItemListener(workItemListener); |
| atsIdProvider.setAtsId(changes); |
| } |
| |
| @Override |
| public String getActionStateJson(Collection<IAtsWorkItem> workItems) { |
| try { |
| ActionServiceOperations ops = new ActionServiceOperations(atsApi); |
| return ops.getActionStateJson(workItems, getJsonFactory()); |
| } catch (Exception ex) { |
| throw OseeCoreException.wrap(ex); |
| } |
| } |
| |
| private JsonFactory getJsonFactory() { |
| if (jsonFactory == null) { |
| jsonFactory = JsonUtil.getFactory(); |
| } |
| return jsonFactory; |
| } |
| |
| public IWorkItemListener getWorkItemListener() { |
| return workItemListener; |
| } |
| |
| public void setWorkItemListener(IWorkItemListener workItemListener) { |
| this.workItemListener = workItemListener; |
| } |
| |
| public void addActionListener(INewActionListener listener) { |
| actionListeners.add(listener); |
| } |
| |
| @Override |
| public IAtsGoal createGoal(String title, IAtsChangeSet changes) { |
| WorkDefinition workDef = |
| atsApi.getWorkDefinitionService().getWorkDefinition(AtsWorkDefinitionTokens.WorkDef_Goal); |
| return createGoal(title, AtsArtifactTypes.Goal, workDef, atsApi.getTeamDefinitionService().getTopTeamDefinition(), |
| changes, null); |
| } |
| |
| @Override |
| public IAtsGoal createGoal(String title, ArtifactTypeToken artifactType, WorkDefinition workDefinition, |
| IAtsTeamDefinition teamDef, IAtsChangeSet changes, IWorkItemListener workItemListener) { |
| ArtifactToken art = changes.createArtifact(artifactType, title); |
| IAtsGoal goal = atsApi.getWorkItemService().getGoal(art); |
| |
| if (goal == null) { |
| throw new OseeCoreException( |
| "In AtsActionService.createGoal, the local vairable \"goal\" is null which is dereferenced"); |
| } |
| |
| Conditions.assertNotNull(teamDef, "Team Definition can not be null for %s", goal.toStringWithId()); |
| atsApi.getActionService().setAtsId(goal, teamDef, workItemListener, changes); |
| |
| WorkDefinition useWorkDefinition = workDefinition; |
| if (useWorkDefinition == null) { |
| useWorkDefinition = atsApi.getWorkDefinitionService().getWorkDefinition(AtsWorkDefinitionTokens.WorkDef_Goal); |
| } |
| Conditions.assertNotNull(workDefinition, "Work Definition can not be null for %s", goal.toStringWithId()); |
| atsApi.getWorkDefinitionService().setWorkDefinitionAttrs(goal, workDefinition, changes); |
| |
| atsApi.getActionService().initializeNewStateMachine(goal, Arrays.asList(atsApi.getUserService().getCurrentUser()), |
| new Date(), atsApi.getUserService().getCurrentUser(), workDefinition, changes); |
| |
| return goal; |
| } |
| } |