diff options
author | ddunne | 2011-05-11 18:08:50 +0000 |
---|---|---|
committer | Ryan D. Brooks | 2011-05-11 18:08:50 +0000 |
commit | 54c315ffd1e76a961a168b14804a6d1e5b8b7ffb (patch) | |
tree | 41398d44c6acc8224b4764ebb52dbd7f409b18d0 /plugins/org.eclipse.osee.ats.core/src/org | |
parent | 9441dccf757f7d6bcceb41a698804b042cc531f6 (diff) | |
download | org.eclipse.osee-54c315ffd1e76a961a168b14804a6d1e5b8b7ffb.tar.gz org.eclipse.osee-54c315ffd1e76a961a168b14804a6d1e5b8b7ffb.tar.xz org.eclipse.osee-54c315ffd1e76a961a168b14804a6d1e5b8b7ffb.zip |
feature: Create ats.core
Diffstat (limited to 'plugins/org.eclipse.osee.ats.core/src/org')
113 files changed, 13018 insertions, 0 deletions
diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/access/AtsBranchAccessContextId.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/access/AtsBranchAccessContextId.java new file mode 100644 index 00000000000..20e91108cd3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/access/AtsBranchAccessContextId.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.access; + +import org.eclipse.osee.framework.core.data.IAccessContextId; +import org.eclipse.osee.framework.core.data.TokenFactory; + +/** + * @author Donald G. Dunne + */ +public final class AtsBranchAccessContextId { + + public static final IAccessContextId DEFAULT_BRANCH_CONTEXT = TokenFactory.createAccessContextId( + "AFRkIhi2m2cdanu3i2AA", "ats.branchobject.default.context"); + public static final IAccessContextId DENY_CONTEXT = TokenFactory.createAccessContextId("ABcgU0QxFG_cQU4Ph1wA", + "ats.branchobject.deny"); + + private AtsBranchAccessContextId() { + // Branch Object Contexts; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/artifact/AbstractAtsArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/artifact/AbstractAtsArtifact.java new file mode 100644 index 00000000000..270b23c4a1c --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/artifact/AbstractAtsArtifact.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.artifact; + +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; + +public abstract class AbstractAtsArtifact extends Artifact { + + public AbstractAtsArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + @SuppressWarnings("unused") + public Artifact getParentAtsArtifact() throws OseeCoreException { + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/AtsBranchManagerCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/AtsBranchManagerCore.java new file mode 100644 index 00000000000..ea4090517f8 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/AtsBranchManagerCore.java @@ -0,0 +1,415 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.branch; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.eclipse.osee.ats.core.commit.ICommitConfigArtifact; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.version.VersionArtifact; +import org.eclipse.osee.framework.core.enums.BranchState; +import org.eclipse.osee.framework.core.enums.BranchType; +import org.eclipse.osee.framework.core.exception.MultipleBranchesExist; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.model.TransactionRecord; +import org.eclipse.osee.framework.core.model.cache.BranchFilter; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; +import org.eclipse.osee.framework.skynet.core.conflict.ConflictManagerExternal; +import org.eclipse.osee.framework.skynet.core.transaction.TransactionManager; + +/** + * @author Donald G. Dunne + */ +public class AtsBranchManagerCore { + + private static Map<String, Branch> hridToWorkingBranchCache = new HashMap<String, Branch>(); + private static Map<String, Long> hridToWorkingBranchCacheUpdated = new HashMap<String, Long>(50); + public static Set<Branch> branchesInCommit = new HashSet<Branch>(); + + /** + * Return working branch associated with SMA whether it is committed or not; This data is cached across all workflows + * with the cache being updated by local and remote events. + */ + public static Branch getWorkingBranch(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + long now = new Date().getTime(); + boolean notSet = hridToWorkingBranchCacheUpdated.get(teamArt.getHumanReadableId()) == null; + if (notSet || (now - hridToWorkingBranchCacheUpdated.get(teamArt.getHumanReadableId()) > 1000)) { + hridToWorkingBranchCache.put(teamArt.getHumanReadableId(), + getWorkingBranchExcludeStates(teamArt, BranchState.REBASELINED, BranchState.DELETED)); + hridToWorkingBranchCacheUpdated.put(teamArt.getHumanReadableId(), now); + } + return hridToWorkingBranchCache.get(teamArt.getHumanReadableId()); + } + + /** + * Return working branch associated with SMA, even if it's been archived; This data is cached across all workflows + * with the cache being updated by local and remote events. Filters out rebaseline branches (which are working + * branches also). + */ + public static Branch getWorkingBranchExcludeStates(TeamWorkFlowArtifact teamArt, BranchState... negatedBranchStates) throws OseeCoreException { + BranchFilter branchFilter = new BranchFilter(BranchType.WORKING, BranchType.BASELINE); + branchFilter.setNegatedBranchStates(negatedBranchStates); + branchFilter.setAssociatedArtifact(teamArt); + + List<Branch> branches = BranchManager.getBranches(branchFilter); + + if (branches.isEmpty()) { + return null; + } else if (branches.size() > 1) { + throw new MultipleBranchesExist( + "Unexpected multiple associated un-deleted working branches found for workflow [%s]", + teamArt.getHumanReadableId()); + } else { + return branches.get(0); + } + } + + /** + * @return whether there is a working branch that is not committed + */ + public static boolean isWorkingBranchInWork(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Branch branch = getWorkingBranch(teamArt); + return branch != null && !branch.getBranchState().isCommitted(); + } + + /** + * Return true if merge branch exists in DB (whether archived or not) + */ + public static boolean isMergeBranchExists(TeamWorkFlowArtifact teamArt, Branch destinationBranch) throws OseeCoreException { + return isMergeBranchExists(teamArt, getWorkingBranch(teamArt), destinationBranch); + } + + /** + * Method available for optimized checking of merge branches so don't have to re-acquire working branch if already + * have + */ + public static boolean isMergeBranchExists(TeamWorkFlowArtifact teamArt, Branch workingBranch, Branch destinationBranch) throws OseeCoreException { + if (workingBranch == null) { + return false; + } + return BranchManager.doesMergeBranchExist(workingBranch, destinationBranch); + } + + public static boolean isMergeCompleted(TeamWorkFlowArtifact teamArt, Branch destinationBranch) throws OseeCoreException { + ConflictManagerExternal conflictManager = + new ConflictManagerExternal(destinationBranch, getWorkingBranch(teamArt)); + return !conflictManager.remainingConflictsExist(); + } + + public static TransactionRecord getCommitTransactionRecord(TeamWorkFlowArtifact teamArt, ICommitConfigArtifact configArt) throws OseeCoreException { + Branch branch = configArt.getParentBranch(); + if (branch == null) { + return null; + } + + Collection<TransactionRecord> transactions = TransactionManager.getCommittedArtifactTransactionIds(teamArt); + for (TransactionRecord transId : transactions) { + if (transId.getBranchId() == branch.getId()) { + return transId; + } + } + return null; + } + + public static CommitStatus getCommitStatus(TeamWorkFlowArtifact teamArt, ICommitConfigArtifact configArt) throws OseeCoreException { + Branch desinationBranch = configArt.getParentBranch(); + if (desinationBranch == null) { + return CommitStatus.Branch_Not_Configured; + } + + Collection<TransactionRecord> transactions = TransactionManager.getCommittedArtifactTransactionIds(teamArt); + boolean mergeBranchExists = AtsBranchManagerCore.isMergeBranchExists(teamArt, desinationBranch); + + for (TransactionRecord transId : transactions) { + if (desinationBranch.equals(transId.getBranch())) { + if (mergeBranchExists) { + return CommitStatus.Committed_With_Merge; + } else { + return CommitStatus.Committed; + } + } + } + + Result result = AtsBranchManagerCore.isCommitBranchAllowed(teamArt, configArt); + if (result.isFalse()) { + return CommitStatus.Branch_Commit_Disabled; + } + if (AtsBranchManagerCore.getWorkingBranch(teamArt) == null) { + return CommitStatus.Working_Branch_Not_Created; + } + if (mergeBranchExists) { + return CommitStatus.Merge_In_Progress; + } + return CommitStatus.Commit_Needed; + } + + public static Result isCommitBranchAllowed(TeamWorkFlowArtifact teamArt, ICommitConfigArtifact configArt) throws OseeCoreException { + if (!teamArt.isTeamWorkflow()) { + return Result.FalseResult; + } + if (teamArt.getTeamDefinition().isTeamUsesVersions()) { + if (teamArt.getTargetedVersion() == null) { + return new Result(false, "Workflow not targeted for Version"); + } + Result result = teamArt.getTargetedVersion().isCommitBranchAllowed(); + if (result.isFalse()) { + return result; + } + + if (teamArt.getTargetedVersion().getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Version [" + teamArt.getTargetedVersion() + "]"); + } + return Result.TrueResult; + + } else { + Result result = teamArt.getTeamDefinition().isCommitBranchAllowed(); + if (result.isFalse()) { + return result; + } + + if (teamArt.getTeamDefinition().getParentBranch() == null) { + return new Result(false, + "Parent Branch not configured for Team Definition [" + teamArt.getTeamDefinition() + "]"); + } + return Result.TrueResult; + } + } + + public static Result isCreateBranchAllowed(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + if (!teamArt.isTeamWorkflow()) { + return Result.FalseResult; + } + + if (teamArt.getTeamDefinition().isTeamUsesVersions()) { + if (teamArt.getTargetedVersion() == null) { + return new Result(false, "Workflow not targeted for Version"); + } + Result result = teamArt.getTargetedVersion().isCreateBranchAllowed(); + if (result.isFalse()) { + return result; + } + + if (teamArt.getTargetedVersion().getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Version [" + teamArt.getTargetedVersion() + "]"); + } + if (!teamArt.getTargetedVersion().getParentBranch().getBranchType().isBaselineBranch()) { + return new Result(false, "Parent Branch must be of Baseline branch type. See Admin for configuration."); + } + return Result.TrueResult; + + } else { + Result result = teamArt.getTeamDefinition().isCreateBranchAllowed(); + if (result.isFalse()) { + return result; + } + + if (teamArt.getTeamDefinition().getParentBranch() == null) { + return new Result(false, + "Parent Branch not configured for Team Definition [" + teamArt.getTeamDefinition() + "]"); + } + if (!teamArt.getTeamDefinition().getParentBranch().getBranchType().isBaselineBranch()) { + return new Result(false, "Parent Branch must be of Baseline branch type. See Admin for configuration."); + } + return Result.TrueResult; + } + } + + /** + * Returns true if there was ever a commit of a working branch regardless of whether the working branch is archived + * or not. + */ + public static boolean isWorkingBranchEverCommitted(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + return getBranchesCommittedTo(teamArt).size() > 0; + } + + public static Collection<ICommitConfigArtifact> getConfigArtifactsConfiguredToCommitTo(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Set<ICommitConfigArtifact> configObjects = new HashSet<ICommitConfigArtifact>(); + if (teamArt.isTeamUsesVersions()) { + if (teamArt.getTargetedVersion() != null) { + teamArt.getTargetedVersion().getParallelVersions(configObjects); + } + } else { + if (teamArt.isTeamWorkflow() && teamArt.getTeamDefinition().getParentBranch() != null) { + configObjects.add(teamArt.getTeamDefinition()); + } + } + return configObjects; + } + + public static ICommitConfigArtifact getParentBranchConfigArtifactConfiguredToCommitTo(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + if (teamArt.isTeamUsesVersions()) { + if (teamArt.getTargetedVersion() != null) { + return teamArt.getTargetedVersion(); + } + } else { + if (teamArt.isTeamWorkflow() && teamArt.getTeamDefinition().getParentBranch() != null) { + return teamArt.getTeamDefinition(); + } + } + return null; + } + + public static boolean isAllObjectsToCommitToConfigured(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + return getConfigArtifactsConfiguredToCommitTo(teamArt).size() == getBranchesToCommitTo(teamArt).size(); + } + + public static Collection<Branch> getBranchesLeftToCommit(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Set<Branch> branchesLeft = new HashSet<Branch>(); + Collection<Branch> committedTo = getBranchesCommittedTo(teamArt); + for (Branch branchToCommit : getBranchesToCommitTo(teamArt)) { + if (!committedTo.contains(branchToCommit)) { + branchesLeft.add(branchToCommit); + } + } + return branchesLeft; + } + + public static Collection<Branch> getBranchesToCommitTo(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Set<Branch> branches = new HashSet<Branch>(); + for (Object obj : getConfigArtifactsConfiguredToCommitTo(teamArt)) { + if (obj instanceof VersionArtifact && ((VersionArtifact) obj).getParentBranch() != null) { + branches.add(((VersionArtifact) obj).getParentBranch()); + } else if (obj instanceof TeamDefinitionArtifact && ((TeamDefinitionArtifact) obj).getParentBranch() != null) { + branches.add(((TeamDefinitionArtifact) obj).getParentBranch()); + } + } + return branches; + } + + public static Collection<Branch> getBranchesCommittedTo(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Set<Branch> branches = new HashSet<Branch>(); + for (TransactionRecord transId : getTransactionIds(teamArt, false)) { + branches.add(transId.getBranch()); + } + return branches; + } + + /** + * @return true if there is at least one destination branch committed to + */ + public static boolean isCommittedBranchExists(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + return isAllObjectsToCommitToConfigured(teamArt) && !getBranchesCommittedTo(teamArt).isEmpty(); + } + + /** + * Return true if all commit destination branches are configured and have been committed to + */ + public static boolean isBranchesAllCommitted(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Collection<Branch> committedTo = getBranchesCommittedTo(teamArt); + for (Branch destBranch : getBranchesToCommitTo(teamArt)) { + if (!committedTo.contains(destBranch)) { + return false; + } + } + return true; + } + + public static boolean isBranchesAllCommittedExcept(TeamWorkFlowArtifact teamArt, Branch branchToExclude) throws OseeCoreException { + Collection<Branch> committedTo = getBranchesCommittedTo(teamArt); + for (Branch destBranch : getBranchesToCommitTo(teamArt)) { + if (!destBranch.equals(branchToExclude) && !committedTo.contains(destBranch)) { + return false; + } + } + return true; + } + + /** + * @return Branch that is the configured branch to create working branch from. + */ + public static Branch getConfiguredBranchForWorkflow(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Branch parentBranch = null; + + // Check for parent branch id in Version artifact + if (teamArt.isTeamUsesVersions()) { + VersionArtifact verArt = teamArt.getTargetedVersion(); + if (verArt != null) { + parentBranch = verArt.getParentBranch(); + } + } + + // If not defined in version, check for parent branch from team definition + if (parentBranch == null && teamArt.isTeamWorkflow()) { + parentBranch = teamArt.getTeamDefinition().getParentBranch(); + } + + // If not defined, return null + return parentBranch; + } + + public static boolean isBranchInCommit(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + if (!isWorkingBranchInWork(teamArt)) { + return false; + } + return branchesInCommit.contains(getWorkingBranch(teamArt)); + } + + public static Integer getId(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Branch branch = getWorkingBranch(teamArt); + if (branch == null) { + return null; + } + return branch.getId(); + } + + private static Collection<TransactionRecord> getCommitTransactionsToUnarchivedBaslineBranchs(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Collection<TransactionRecord> committedTransactions = + TransactionManager.getCommittedArtifactTransactionIds(teamArt); + + Collection<TransactionRecord> transactionIds = new ArrayList<TransactionRecord>(); + for (TransactionRecord transactionId : committedTransactions) { + // exclude working branches including branch states that are re-baselined + Branch branch = transactionId.getBranch(); + if (branch.getBranchType().isBaselineBranch() && branch.getArchiveState().isUnArchived()) { + transactionIds.add(transactionId); + } + } + return transactionIds; + } + + /** + * @return TransactionId associated with this state machine artifact + */ + public static Collection<TransactionRecord> getTransactionIds(TeamWorkFlowArtifact teamArt, boolean forMergeBranches) throws OseeCoreException { + if (forMergeBranches) { + Branch workingBranch = getWorkingBranch(teamArt); + // grab only the transaction that had merge conflicts + Collection<TransactionRecord> transactionIds = new ArrayList<TransactionRecord>(); + for (TransactionRecord transactionId : getCommitTransactionsToUnarchivedBaslineBranchs(teamArt)) { + if (isMergeBranchExists(teamArt, workingBranch, transactionId.getBranch())) { + transactionIds.add(transactionId); + } + } + return transactionIds; + } else { + return getCommitTransactionsToUnarchivedBaslineBranchs(teamArt); + } + } + + public static TransactionRecord getEarliestTransactionId(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Collection<TransactionRecord> transactionIds = getTransactionIds(teamArt, false); + if (transactionIds.size() == 1) { + return transactionIds.iterator().next(); + } + TransactionRecord earliestTransactionId = transactionIds.iterator().next(); + for (TransactionRecord transactionId : transactionIds) { + if (transactionId.getId() < earliestTransactionId.getId()) { + earliestTransactionId = transactionId; + } + } + return earliestTransactionId; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/CommitStatus.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/CommitStatus.java new file mode 100644 index 00000000000..119140b0e2b --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/branch/CommitStatus.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.branch; + +/** + * @author Donald G. Dunne + */ +public enum CommitStatus { + Working_Branch_Not_Created("Working Branch Not Created"), + Branch_Not_Configured("Branch Not Configured"), + Branch_Commit_Disabled("Branch Commit Disabled"), + Commit_Needed("Start Commit"), + Merge_In_Progress("Merge in Progress"), + Committed("Committed"), + Committed_With_Merge("Committed With Merge"); + + private final String displayName; + + private CommitStatus(String displayName) { + this.displayName = displayName; + } + + /** + * @return the displayName + */ + public String getDisplayName() { + return displayName; + } +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/commit/ICommitConfigArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/commit/ICommitConfigArtifact.java new file mode 100644 index 00000000000..cee30940a46 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/commit/ICommitConfigArtifact.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.commit; + +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.util.Result; + +/** + * @author Donald G. Dunne + */ +public interface ICommitConfigArtifact { + + public Branch getParentBranch() throws OseeCoreException; + + public Result isCommitBranchAllowed() throws OseeCoreException; + + public Result isCreateBranchAllowed() throws OseeCoreException; + + public String getFullDisplayName() throws OseeCoreException; + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/ActionableItemArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/ActionableItemArtifact.java new file mode 100644 index 00000000000..9da88170f9a --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/ActionableItemArtifact.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.config; + +import java.util.Arrays; +import java.util.Collection; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; + +/** + * @author Donald G. Dunne + */ +public class ActionableItemArtifact extends Artifact { + + public ActionableItemArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + public Collection<User> getLeads() throws OseeCoreException { + return getRelatedArtifacts(AtsRelationTypes.TeamLead_Lead, User.class); + } + + public boolean isActionable() throws OseeCoreException { + return getSoleAttributeValue(AtsAttributeTypes.Actionable, false); + } + + public Collection<TeamDefinitionArtifact> getImpactedTeamDefs() throws OseeCoreException { + return TeamDefinitionManagerCore.getImpactedTeamDefs(Arrays.asList(this)); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsArtifactToken.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsArtifactToken.java new file mode 100644 index 00000000000..6e392d8cc19 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsArtifactToken.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.config; + +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.framework.core.data.IArtifactToken; +import org.eclipse.osee.framework.core.data.TokenFactory; +import org.eclipse.osee.framework.core.enums.CoreArtifactTypes; + +public final class AtsArtifactToken { + + public static IArtifactToken HeadingFolder = TokenFactory.createArtifactToken("AAABER+3yR4A8O7WYQ+Xbw", + "Action Tracking System", CoreArtifactTypes.Folder); + public static IArtifactToken TopTeamDefinition = TokenFactory.createArtifactToken("AAABER+35b4A8O7WHrXTiA", "Teams", + AtsArtifactTypes.TeamDefinition); + public static IArtifactToken TopActionableItem = TokenFactory.createArtifactToken("AAABER+37QEA8O7WSQaqJQ", + "Actionable Items", AtsArtifactTypes.ActionableItem); + public static IArtifactToken ConfigFolder = TokenFactory.createArtifactToken("AAABF4n18eYAc1ruQSSWdg", "Config", + CoreArtifactTypes.Folder); + public static IArtifactToken WorkDefinitionsFolder = TokenFactory.createArtifactToken("ADTfjCLEj2DH2WYyeOgA", + "Work Definitions", CoreArtifactTypes.Folder); + public static IArtifactToken WorkPagesFolder = TokenFactory.createArtifactToken("AAABGnncY_gAAo+3N69ASA", + "Work Pages", CoreArtifactTypes.Folder); + public static IArtifactToken WorkRulesFolder = TokenFactory.createArtifactToken("AAABGnmhCyYAoJoIciyaag", + "Work Rules", CoreArtifactTypes.Folder); + public static IArtifactToken WorkWidgetsFolder = TokenFactory.createArtifactToken("AAABGnmjk4IAoJoIa945Kg", + "Work Widgets", CoreArtifactTypes.Folder); + public static IArtifactToken WorkFlowsFolder = TokenFactory.createArtifactToken("AAABGnncZ_4AAo+3D0sGfw", + "Work Flows", CoreArtifactTypes.Folder); + + private AtsArtifactToken() { + // Constants + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsBulkLoad.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsBulkLoad.java new file mode 100644 index 00000000000..9e392fbe78c --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsBulkLoad.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.config; + +import java.util.Collection; +import java.util.Set; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.operation.EmptyOperation; +import org.eclipse.osee.framework.core.operation.IOperation; +import org.eclipse.osee.framework.core.operation.Operations; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.relation.RelationManager; + +/** + * @author Donald G. Dunne + */ +public class AtsBulkLoad { + + private static boolean atsTypeDataLoadedStarted = false; + + public synchronized static IOperation getConfigLoadingOperation() { + if (atsTypeDataLoadedStarted == false) { + atsTypeDataLoadedStarted = true; + return new AtsLoadConfigArtifactsOperation(); + } + return new EmptyOperation("ATS Bulk Loading", Activator.PLUGIN_ID); + } + + public static void reloadConfig(boolean pend) { + if (pend) { + Operations.executeWork(new AtsLoadConfigArtifactsOperation()); + } else { + Operations.executeAsJob(new AtsLoadConfigArtifactsOperation(), false); + } + } + + public static void loadConfig(boolean pend) { + if (AtsLoadConfigArtifactsOperation.isLoaded()) { + return; + } + reloadConfig(pend); + } + + public static Set<Artifact> loadFromActions(Collection<? extends Artifact> actions) throws OseeCoreException { + return RelationManager.getRelatedArtifacts(actions, 4, AtsRelationTypes.SmaToTask_Task, + AtsRelationTypes.ActionToWorkflow_WorkFlow, AtsRelationTypes.TeamWorkflowToReview_Review); + } + + public static Set<Artifact> loadFromTeamWorkflows(Collection<? extends Artifact> teams) throws OseeCoreException { + return RelationManager.getRelatedArtifacts(teams, 3, AtsRelationTypes.SmaToTask_Task, + AtsRelationTypes.TeamWorkflowToReview_Team, AtsRelationTypes.ActionToWorkflow_Action); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsLoadConfigArtifactsOperation.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsLoadConfigArtifactsOperation.java new file mode 100644 index 00000000000..6d78deff33b --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/AtsLoadConfigArtifactsOperation.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.config; + +import java.util.Collections; +import java.util.logging.Level; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.enums.CoreRelationTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.operation.AbstractOperation; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.relation.RelationManager; + +/** + * @author Donald G. Dunne + */ +public class AtsLoadConfigArtifactsOperation extends AbstractOperation { + private static boolean loaded = false; + + public AtsLoadConfigArtifactsOperation() { + super("ATS Loading Configuration", Activator.PLUGIN_ID); + } + + public void forceReload() throws OseeCoreException { + loaded = false; + ensureLoaded(); + } + + public synchronized void ensureLoaded() throws OseeCoreException { + if (!loaded) { + loaded = true; + OseeLog.log(Activator.class, Level.INFO, "Loading ATS Configuration"); + Artifact headingArt = AtsUtilCore.getFromToken(AtsArtifactToken.HeadingFolder); + // Loading artifacts will cache them in ArtifactCache + RelationManager.getRelatedArtifacts(Collections.singleton(headingArt), 8, + CoreRelationTypes.Default_Hierarchical__Child, AtsRelationTypes.TeamDefinitionToVersion_Version); + // Load Work Definitions + // TODO not doing anymore + // WorkItemDefinitionFactory.loadDefinitions(); + loaded = true; + } + } + + @Override + protected void doWork(IProgressMonitor monitor) throws Exception { + ensureLoaded(); + } + + public static boolean isLoaded() { + return loaded; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionArtifact.java new file mode 100644 index 00000000000..fae43912a82 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionArtifact.java @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.config; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.commit.ICommitConfigArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.version.VersionArtifact; +import org.eclipse.osee.ats.core.version.VersionLockedType; +import org.eclipse.osee.ats.core.version.VersionReleaseType; +import org.eclipse.osee.ats.core.workdef.RuleDefinition; +import org.eclipse.osee.ats.core.workdef.RuleDefinitionOption; +import org.eclipse.osee.ats.core.workdef.RuleManager; +import org.eclipse.osee.ats.core.workdef.WorkDefinitionFactory; +import org.eclipse.osee.ats.core.workdef.WorkDefinitionMatch; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.enums.CoreArtifactTypes; +import org.eclipse.osee.framework.core.enums.CoreRelationTypes; +import org.eclipse.osee.framework.core.exception.BranchDoesNotExist; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.jdk.core.util.GUID; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactTypeManager; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; + +/** + * @author Donald G. Dunne + */ +public class TeamDefinitionArtifact extends Artifact implements ICommitConfigArtifact { + + public TeamDefinitionArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + @Override + public Result isCreateBranchAllowed() throws OseeCoreException { + if (!getSoleAttributeValue(AtsAttributeTypes.AllowCreateBranch, false)) { + return new Result(false, "Branch creation disabled for Team Definition [" + this + "]"); + } + if (getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Team Definition [" + this + "]"); + } + return Result.TrueResult; + } + + @Override + public Result isCommitBranchAllowed() throws OseeCoreException { + if (!getSoleAttributeValue(AtsAttributeTypes.AllowCommitBranch, false)) { + return new Result(false, "Team Definition [" + this + "] not configured to allow branch commit."); + } + if (getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Team Definition [" + this + "]"); + } + return Result.TrueResult; + } + + public void initialize(String fullname, String description, Collection<User> leads, Collection<User> members, Collection<ActionableItemArtifact> actionableItems, TeamDefinitionOptions... teamDefinitionOptions) throws OseeCoreException { + List<Object> teamDefOptions = Collections.getAggregate((Object[]) teamDefinitionOptions); + + setSoleAttributeValue(AtsAttributeTypes.Description, description); + setSoleAttributeValue(AtsAttributeTypes.FullName, fullname); + for (User user : leads) { + addRelation(AtsRelationTypes.TeamLead_Lead, user); + // All leads are members + addRelation(AtsRelationTypes.TeamMember_Member, user); + } + for (User user : members) { + addRelation(AtsRelationTypes.TeamMember_Member, user); + } + + if (teamDefOptions.contains(TeamDefinitionOptions.TeamUsesVersions)) { + setSoleAttributeValue(AtsAttributeTypes.TeamUsesVersions, true); + } + if (teamDefOptions.contains(TeamDefinitionOptions.RequireTargetedVersion)) { + addRule(RuleDefinitionOption.RequireTargetedVersion); + } + + // Relate to actionable items + for (ActionableItemArtifact aia : actionableItems) { + addRelation(AtsRelationTypes.TeamActionableItem_ActionableItem, aia); + } + } + + @Override + public Branch getParentBranch() throws OseeCoreException { + try { + String guid = getSoleAttributeValue(AtsAttributeTypes.BaselineBranchGuid, ""); + if (GUID.isValid(guid)) { + return BranchManager.getBranchByGuid(guid); + } + } catch (BranchDoesNotExist ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return null; + } + + /** + * This method will walk up the TeamDefinition tree until a def is found that configured with versions. This allows + * multiple TeamDefinitions to be versioned/released together by having the parent hold the versions. It is not + * required that a product configured in ATS uses the versions option. If no parent with versions is found, null is + * returned. If boolean "Team Uses Versions" is false, just return cause this team doesn't use versions + * + * @return parent TeamDefinition that holds the version definitions + */ + public TeamDefinitionArtifact getTeamDefinitionHoldingVersions() throws OseeCoreException { + if (!isTeamUsesVersions()) { + return null; + } + if (getVersionsArtifacts().size() > 0) { + return this; + } + if (getParent() instanceof TeamDefinitionArtifact) { + TeamDefinitionArtifact parentTda = (TeamDefinitionArtifact) getParent(); + if (parentTda != null) { + return parentTda.getTeamDefinitionHoldingVersions(); + } + } + return null; + } + + /** + * This method will walk up the TeamDefinition tree until a def is found that configured with work flow. + * + * @return parent TeamDefinition that holds the work flow id attribute + */ + public TeamDefinitionArtifact getTeamDefinitionHoldingWorkFlow() throws OseeCoreException { + for (Artifact artifact : getRelatedArtifacts(CoreRelationTypes.WorkItem__Child, Artifact.class)) { + if (artifact.isOfType(CoreArtifactTypes.WorkFlowDefinition)) { + return this; + } + } + if (getParent() instanceof TeamDefinitionArtifact) { + TeamDefinitionArtifact parentTda = (TeamDefinitionArtifact) getParent(); + if (parentTda != null) { + return parentTda.getTeamDefinitionHoldingWorkFlow(); + } + } + return null; + } + + public Artifact getNextReleaseVersion() throws OseeCoreException { + for (Artifact verArt : getRelatedArtifacts(AtsRelationTypes.TeamDefinitionToVersion_Version)) { + if (verArt.getSoleAttributeValue(AtsAttributeTypes.NextVersion, false)) { + return verArt; + } + } + return null; + } + + public Collection<VersionArtifact> getVersionsFromTeamDefHoldingVersions(VersionReleaseType releaseType, VersionLockedType lockedType) throws OseeCoreException { + TeamDefinitionArtifact teamDef = getTeamDefinitionHoldingVersions(); + if (teamDef == null) { + return new ArrayList<VersionArtifact>(); + } + return teamDef.getVersionsArtifacts(releaseType, lockedType); + } + + public double getManDayHrsFromItemAndChildren() { + return getHoursPerWorkDayFromItemAndChildren(this); + } + + public Artifact getWorkflowArtifact(Artifact teamDef) throws OseeCoreException { + Artifact workFlowArt = null; + for (Artifact artifact : teamDef.getRelatedArtifacts(CoreRelationTypes.WorkItem__Child, Artifact.class)) { + if (artifact.isOfType(CoreArtifactTypes.WorkFlowDefinition)) { + if (workFlowArt != null) { + OseeLog.log( + Activator.class, + Level.SEVERE, + "Multiple workflows found where only one expected for Team Definition " + getHumanReadableId() + " - " + getName()); + } + workFlowArt = artifact; + } + } + return workFlowArt; + } + + public WorkDefinitionMatch getWorkDefinition() throws OseeCoreException { + Artifact teamDef = getTeamDefinitionHoldingWorkFlow(); + if (teamDef == null) { + return null; + } + Artifact workFlowArt = getWorkflowArtifact(teamDef); + if (workFlowArt == null) { + return null; + } + WorkDefinitionMatch match = WorkDefinitionFactory.getWorkDefinition(workFlowArt.getName()); + if (match.isMatched()) { + match.addTrace(String.format("from teamDef [%s] related work child [%s]", teamDef, workFlowArt.getName())); + } + return match; + } + + /** + * If hours per work day attribute is set, use it, otherwise, walk up the Team Definition tree. Value used in + * calculations. + */ + public double getHoursPerWorkDayFromItemAndChildren(TeamDefinitionArtifact teamDef) { + try { + Double manDaysHrs = teamDef.getSoleAttributeValue(AtsAttributeTypes.HoursPerWorkDay, 0.0); + if (manDaysHrs != null && manDaysHrs != 0) { + return manDaysHrs; + } + if (teamDef.getParent() instanceof TeamDefinitionArtifact) { + return teamDef.getHoursPerWorkDayFromItemAndChildren((TeamDefinitionArtifact) teamDef.getParent()); + } + return AtsUtilCore.DEFAULT_HOURS_PER_WORK_DAY; + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return 0.0; + } + + /** + * Return ONLY leads configured for this TeamDefinitionArtifact. Depending on the use, like creating new actions, the + * assignees (or Leads) are determined first from users configured as leads of individual actionable items and only + * if that returns no leads, THEN default to using the leads configured for the TeamDefinition. In these cases, use + * getLeads(Collection<ActionableItemArtifact>) instead. + * + * @return users configured as leads for this TeamDefinitionArtifact + */ + public Collection<User> getLeads() throws OseeCoreException { + return getRelatedArtifacts(AtsRelationTypes.TeamLead_Lead, User.class); + } + + public Collection<User> getPrivilegedMembers() throws OseeCoreException { + return getRelatedArtifacts(AtsRelationTypes.PrivilegedMember_Member, User.class); + } + + /** + * Returns leads configured first by ActionableItems and only if this is an empty set, THEN defaults to those + * configured by TeamDefinitions. Use getLeads() to only get the leads configured for this TeamDefinitionArtifact. + * + * @return users configured as leads by ActionableItems, then by TeamDefinition + */ + public Collection<User> getLeads(Collection<ActionableItemArtifact> actionableItems) throws OseeCoreException { + Set<User> leads = new HashSet<User>(); + for (ActionableItemArtifact aia : actionableItems) { + if (aia.getImpactedTeamDefs().contains(this)) { + // If leads are specified for this aia, add them + if (aia.getLeads().size() > 0) { + leads.addAll(aia.getLeads()); + } else { + for (TeamDefinitionArtifact teamDef : aia.getImpactedTeamDefs()) { + leads.addAll(teamDef.getLeads()); + } + } + } + } + if (leads.isEmpty()) { + leads.addAll(getLeads()); + } + return leads; + } + + @SuppressWarnings("unchecked") + public Collection<User> getMembersAndLeads() throws OseeCoreException { + return Collections.setUnion(getMembers(), getLeads()); + } + + public Collection<User> getMembers() throws OseeCoreException { + return getRelatedArtifacts(AtsRelationTypes.TeamMember_Member, User.class); + } + + public Artifact getVersionArtifact(String name, boolean create) throws OseeCoreException { + for (Artifact verArt : getVersionsArtifacts()) { + if (verArt.getName().equals(name)) { + return verArt; + } + } + if (create) { + return createVersion(name); + } + return null; + } + + public VersionArtifact createVersion(String name) throws OseeCoreException { + VersionArtifact versionArt = + (VersionArtifact) ArtifactTypeManager.addArtifact(AtsArtifactTypes.Version, AtsUtilCore.getAtsBranch(), name); + addRelation(AtsRelationTypes.TeamDefinitionToVersion_Version, versionArt); + return versionArt; + } + + public Collection<VersionArtifact> getVersionsArtifacts() throws OseeCoreException { + return getRelatedArtifacts(AtsRelationTypes.TeamDefinitionToVersion_Version, VersionArtifact.class); + } + + public Collection<VersionArtifact> getVersionsArtifacts(VersionReleaseType releaseType, VersionLockedType lockType) throws OseeCoreException { + return Collections.setIntersection(getVersionsArtifacts(releaseType), getVersionsArtifacts(lockType)); + } + + private Collection<VersionArtifact> getVersionsArtifacts(VersionReleaseType releaseType) throws OseeCoreException { + ArrayList<VersionArtifact> versions = new ArrayList<VersionArtifact>(); + for (VersionArtifact version : getVersionsArtifacts()) { + if (version.isReleased() && (releaseType == VersionReleaseType.Released || releaseType == VersionReleaseType.Both)) { + versions.add(version); + } else if ((!version.isReleased() && releaseType == VersionReleaseType.UnReleased) || releaseType == VersionReleaseType.Both) { + versions.add(version); + } + } + return versions; + } + + private Collection<VersionArtifact> getVersionsArtifacts(VersionLockedType lockType) throws OseeCoreException { + ArrayList<VersionArtifact> versions = new ArrayList<VersionArtifact>(); + for (VersionArtifact version : getVersionsArtifacts()) { + if (version.isVersionLocked() && (lockType == VersionLockedType.Locked || lockType == VersionLockedType.Both)) { + versions.add(version); + } else if ((!version.isVersionLocked() && lockType == VersionLockedType.UnLocked) || lockType == VersionLockedType.Both) { + versions.add(version); + } + } + return versions; + } + + public boolean isTeamUsesVersions() throws OseeCoreException { + return getSoleAttributeValue(AtsAttributeTypes.TeamUsesVersions, false); + } + + public boolean isActionable() throws OseeCoreException { + return getSoleAttributeValue(AtsAttributeTypes.Actionable, false); + } + + public List<RuleDefinition> getWorkRules() throws OseeCoreException { + List<RuleDefinition> rules = new ArrayList<RuleDefinition>(); + for (String ruleId : getAttributesToStringList(AtsAttributeTypes.RuleDefinition)) { + RuleDefinition ruleDef = RuleManager.getOrCreateRule(ruleId); + rules.add(ruleDef); + } + return rules; + } + + public void addRule(RuleDefinitionOption option) throws OseeCoreException { + addRule(option.name()); + } + + public void addRule(String ruleId) throws OseeCoreException { + if (!hasRule(ruleId)) { + addAttribute(AtsAttributeTypes.RuleDefinition, ruleId); + } + } + + public boolean hasRule(RuleDefinitionOption option) throws OseeCoreException { + return hasRule(option.name()); + } + + public boolean hasRule(String ruleId) throws OseeCoreException { + return getAttributesToStringList(AtsAttributeTypes.RuleDefinition).contains(ruleId); + } + + /** + * Returns the branch associated with this team. If this team does not have a branch associated then the parent team + * will be asked, this results in a recursive look at parent teams until a parent artifact has a related branch or + * the parent of a team is not a team. <br/> + * <br/> + * If no branch is associated then null will be returned. + */ + public Branch getTeamBranch() throws OseeCoreException { + String guid = getSoleAttributeValue(AtsAttributeTypes.BaselineBranchGuid, null); + if (GUID.isValid(guid)) { + return BranchManager.getBranchByGuid(guid); + } else { + Artifact parent = getParent(); + if (parent instanceof TeamDefinitionArtifact) { + return ((TeamDefinitionArtifact) parent).getTeamBranch(); + } + } + return null; + } + + @Override + public String getFullDisplayName() { + return getName(); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManager.java new file mode 100644 index 00000000000..65965cc1b5b --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManager.java @@ -0,0 +1,111 @@ +/* + * Created on Mar 24, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.config; + +import static org.eclipse.osee.framework.core.enums.DeletionFlag.EXCLUDE_DELETED; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsCacheManager; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.enums.Active; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; + +public class TeamDefinitionManager { + public static List<TeamDefinitionArtifact> getTopLevelTeamDefinitions(Active active) throws OseeCoreException { + TeamDefinitionArtifact topTeamDef = getTopTeamDefinition(); + if (topTeamDef == null) { + return java.util.Collections.emptyList(); + } + return Collections.castAll(AtsUtilCore.getActive( + Artifacts.getChildrenOfTypeSet(topTeamDef, TeamDefinitionArtifact.class, false), active, + TeamDefinitionArtifact.class)); + } + + public static List<TeamDefinitionArtifact> getTeamDefinitions(Active active) throws OseeCoreException { + return Collections.castAll(AtsCacheManager.getArtifactsByActive(AtsArtifactTypes.TeamDefinition, active)); + } + + public static List<TeamDefinitionArtifact> getTeamTopLevelDefinitions(Active active) throws OseeCoreException { + TeamDefinitionArtifact topTeamDef = getTopTeamDefinition(); + if (topTeamDef == null) { + return java.util.Collections.emptyList(); + } + return Collections.castAll(AtsUtilCore.getActive( + Artifacts.getChildrenOfTypeSet(topTeamDef, TeamDefinitionArtifact.class, false), active, + TeamDefinitionArtifact.class)); + } + + public static TeamDefinitionArtifact getTopTeamDefinition() { + return (TeamDefinitionArtifact) AtsUtilCore.getFromToken(AtsArtifactToken.TopTeamDefinition); + } + + public static Set<TeamDefinitionArtifact> getTeamReleaseableDefinitions(Active active) throws OseeCoreException { + Set<TeamDefinitionArtifact> teamDefs = new HashSet<TeamDefinitionArtifact>(); + for (TeamDefinitionArtifact teamDef : getTeamDefinitions(active)) { + if (teamDef.getVersionsArtifacts().size() > 0) { + teamDefs.add(teamDef); + } + } + return teamDefs; + } + + public static Set<TeamDefinitionArtifact> getTeamsFromItemAndChildren(ActionableItemArtifact aia) throws OseeCoreException { + Set<TeamDefinitionArtifact> aiaTeams = new HashSet<TeamDefinitionArtifact>(); + getTeamFromItemAndChildren(aia, aiaTeams); + return aiaTeams; + } + + public static Set<TeamDefinitionArtifact> getTeamsFromItemAndChildren(TeamDefinitionArtifact teamDef) throws OseeCoreException { + Set<TeamDefinitionArtifact> teamDefs = new HashSet<TeamDefinitionArtifact>(); + teamDefs.add(teamDef); + for (Artifact art : teamDef.getChildren()) { + if (art instanceof TeamDefinitionArtifact) { + teamDefs.addAll(getTeamsFromItemAndChildren((TeamDefinitionArtifact) art)); + } + } + return teamDefs; + } + + private static void getTeamFromItemAndChildren(ActionableItemArtifact aia, Set<TeamDefinitionArtifact> aiaTeams) throws OseeCoreException { + if (aia.getRelatedArtifacts(AtsRelationTypes.TeamActionableItem_Team).size() > 0) { + aiaTeams.addAll(aia.getRelatedArtifacts(AtsRelationTypes.TeamActionableItem_Team, TeamDefinitionArtifact.class)); + } + for (Artifact childArt : aia.getChildren()) { + if (childArt instanceof ActionableItemArtifact) { + getTeamFromItemAndChildren((ActionableItemArtifact) childArt, aiaTeams); + } + } + } + + public static Set<TeamDefinitionArtifact> getTeamDefinitions(Collection<String> teamDefNames) { + Set<TeamDefinitionArtifact> teamDefs = new HashSet<TeamDefinitionArtifact>(); + for (String teamDefName : teamDefNames) { + for (Artifact artifact : AtsCacheManager.getArtifactsByName(AtsArtifactTypes.TeamDefinition, teamDefName)) { + teamDefs.add((TeamDefinitionArtifact) artifact); + } + } + return teamDefs; + } + + public static Set<TeamDefinitionArtifact> getTeamDefinitionsNameStartsWith(String prefix) throws OseeCoreException { + Set<TeamDefinitionArtifact> artifacts = new HashSet<TeamDefinitionArtifact>(); + for (Artifact art : ArtifactQuery.getArtifactListFromName(prefix + "%", AtsUtilCore.getAtsBranch(), + EXCLUDE_DELETED)) { + if (art instanceof TeamDefinitionArtifact) { + artifacts.add((TeamDefinitionArtifact) art); + } + } + return artifacts; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManagerCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManagerCore.java new file mode 100644 index 00000000000..3bce9897728 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionManagerCore.java @@ -0,0 +1,40 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.config; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class TeamDefinitionManagerCore { + + public static Collection<TeamDefinitionArtifact> getImpactedTeamDefs(Collection<ActionableItemArtifact> aias) throws OseeCoreException { + Set<TeamDefinitionArtifact> resultTeams = new HashSet<TeamDefinitionArtifact>(); + for (ActionableItemArtifact aia : aias) { + resultTeams.addAll(getImpactedTeamDefInherited(aia)); + } + return resultTeams; + } + + private static List<TeamDefinitionArtifact> getImpactedTeamDefInherited(ActionableItemArtifact aia) throws OseeCoreException { + if (aia.getRelatedArtifacts(AtsRelationTypes.TeamActionableItem_Team).size() > 0) { + return aia.getRelatedArtifacts(AtsRelationTypes.TeamActionableItem_Team, TeamDefinitionArtifact.class); + } + Artifact parentArt = aia.getParent(); + if (parentArt instanceof ActionableItemArtifact) { + return getImpactedTeamDefInherited((ActionableItemArtifact) parentArt); + } + return java.util.Collections.emptyList(); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionOptions.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionOptions.java new file mode 100644 index 00000000000..b94262db6d3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/config/TeamDefinitionOptions.java @@ -0,0 +1,6 @@ +package org.eclipse.osee.ats.core.config; + +public enum TeamDefinitionOptions { + TeamUsesVersions, + RequireTargetedVersion +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/internal/Activator.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/internal/Activator.java new file mode 100644 index 00000000000..6806f806edc --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/internal/Activator.java @@ -0,0 +1,33 @@ +package org.eclipse.osee.ats.core.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + public static final String PLUGIN_ID = "org.eclipse.osee.ats.core"; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/AbstractReviewArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/AbstractReviewArtifact.java new file mode 100644 index 00000000000..df9d4b0082c --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/AbstractReviewArtifact.java @@ -0,0 +1,240 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.defect.DefectManager; +import org.eclipse.osee.ats.core.review.role.UserRole; +import org.eclipse.osee.ats.core.review.role.UserRoleManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.workdef.ReviewBlockType; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.ActionableItemManagerCore; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public abstract class AbstractReviewArtifact extends AbstractTaskableArtifact { + + protected DefectManager defectManager; + protected UserRoleManager userRoleManager; + private ActionableItemManagerCore actionableItemsDam; + private Collection<UserRole> preSaveReviewRoleComplete; + private Boolean standAlone = null; + + public AbstractReviewArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + @Override + public void onInitializationComplete() throws OseeCoreException { + super.onInitializationComplete(); + initializeSMA(); + }; + + @Override + public void onAttributePersist(SkynetTransaction transaction) { + super.onAttributePersist(transaction); + // Since multiple ways exist to change the assignees, notification is performed on the persist + if (isDeleted()) { + return; + } + try { + notifyReviewersComplete(); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + @Override + public void initalizePreSaveCache() { + super.initalizePreSaveCache(); + try { + preSaveReviewRoleComplete = getRoleUsersReviewComplete(); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + private Collection<UserRole> getRoleUsersReviewComplete() throws OseeCoreException { + return this.getUserRoleManager().getRoleUsersReviewComplete(); + } + + public void notifyReviewersComplete() throws OseeCoreException { + UserRoleManager userRoleManager = this.getUserRoleManager(); + //all reviewers are complete; send notification to author/moderator + // TODO Add this back in once move to ats.core + // if (!preSaveReviewRoleComplete.equals(userRoleManager.getRoleUsersReviewComplete()) && userRoleManager.getUserRoles( + // Role.Reviewer).equals(userRoleManager.getRoleUsersReviewComplete())) { + // AtsNotifyUsers.getInstance().notify(this, AtsNotifyUsers.NotifyType.Reviewed); + // } + preSaveReviewRoleComplete = userRoleManager.getRoleUsersReviewComplete(); + } + + /** + * Reset managers for case where artifact is re-loaded/initialized + * + * @see org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact#initialize() + */ + @Override + protected void initializeSMA() throws OseeCoreException { + super.initializeSMA(); + defectManager = new DefectManager(this); + userRoleManager = new UserRoleManager(this); + actionableItemsDam = new ActionableItemManagerCore(this); + } + + @Override + public String getArtifactSuperTypeName() { + return "Review"; + } + + public boolean isBlocking() throws OseeCoreException { + return getReviewBlockType() != ReviewBlockType.None; + } + + public ReviewBlockType getReviewBlockType() throws OseeCoreException { + String typeStr = getSoleAttributeValue(AtsAttributeTypes.ReviewBlocks, null); + if (typeStr == null) { + // Check old attribute value + if (getSoleAttributeValue(AtsAttributeTypes.BlockingReview, false)) { + return ReviewBlockType.Transition; + } + return ReviewBlockType.None; + } + return ReviewBlockType.valueOf(typeStr); + } + + public DefectManager getDefectManager() { + if (defectManager == null) { + defectManager = new DefectManager(this); + } + return defectManager; + } + + public UserRoleManager getUserRoleManager() { + if (userRoleManager == null) { + return userRoleManager = new UserRoleManager(this); + } + return userRoleManager; + } + + public Set<TeamDefinitionArtifact> getCorrespondingTeamDefinitionArtifact() throws OseeCoreException { + Set<TeamDefinitionArtifact> teamDefs = new HashSet<TeamDefinitionArtifact>(); + if (getParentTeamWorkflow() != null) { + teamDefs.add(getParentTeamWorkflow().getTeamDefinition()); + } + if (getActionableItemsDam().getActionableItems().size() > 0) { + teamDefs.addAll(ActionableItemManagerCore.getImpactedTeamDefs(getActionableItemsDam().getActionableItems())); + } + return teamDefs; + } + + /** + * @return the actionableItemsDam + */ + public ActionableItemManagerCore getActionableItemsDam() throws OseeCoreException { + if (actionableItemsDam == null) { + actionableItemsDam = new ActionableItemManagerCore(this); + } + return actionableItemsDam; + } + + @Override + public AbstractWorkflowArtifact getParentAWA() throws OseeCoreException { + if (isStandAloneReview()) { + return null; + } + if (parentAwa != null) { + return parentAwa; + } + parentAwa = getParentTeamWorkflow(); + return parentAwa; + } + + @Override + public Artifact getParentActionArtifact() throws OseeCoreException { + if (isStandAloneReview()) { + return null; + } + if (parentAction != null) { + return parentAction; + } + parentTeamArt = getParentTeamWorkflow(); + if (parentTeamArt != null) { + parentAction = parentTeamArt.getParentActionArtifact(); + } + return parentAction; + } + + @Override + public TeamWorkFlowArtifact getParentTeamWorkflow() throws OseeCoreException { + if (isStandAloneReview()) { + return null; + } + if (parentTeamArt != null) { + return parentTeamArt; + } + List<TeamWorkFlowArtifact> teams = + getRelatedArtifacts(AtsRelationTypes.TeamWorkflowToReview_Team, TeamWorkFlowArtifact.class); + if (teams.size() > 1) { + OseeLog.log(Activator.class, Level.SEVERE, + getArtifactTypeName() + " " + getHumanReadableId() + " has multiple parent workflows"); + } else if (!isStandAloneReview() && teams.isEmpty()) { + OseeLog.log(Activator.class, Level.SEVERE, + getArtifactTypeName() + " " + getHumanReadableId() + " has no parent workflow"); + } + if (!teams.isEmpty()) { + parentTeamArt = teams.iterator().next(); + } + return parentTeamArt; + } + + public boolean isStandAloneReview() throws OseeCoreException { + if (standAlone == null) { + standAlone = getActionableItemsDam().getActionableItemGuids().size() > 0; + } + return standAlone; + } + + @Override + public double getWorldViewWeeklyBenefit() { + return 0; + } + + public Artifact getArtifact() { + return this; + } + + public static AbstractReviewArtifact cast(Artifact artifact) { + if (artifact instanceof AbstractReviewArtifact) { + return (AbstractReviewArtifact) artifact; + } + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionOption.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionOption.java new file mode 100644 index 00000000000..f95c75552af --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionOption.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.util.Collection; +import java.util.HashSet; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; + +public class DecisionOption { + private String name; + private Collection<User> assignees = new HashSet<User>(); + private boolean followupRequired; + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + name.hashCode(); + + return result; + } + + public DecisionOption(String name, Collection<User> assignees, boolean followup) { + this.name = name; + this.followupRequired = followup; + if (assignees != null) { + this.assignees = assignees; + } + } + + public DecisionOption(String name, User assignee, boolean followup) { + this.name = name; + this.followupRequired = followup; + if (assignee != null) { + this.assignees.add(assignee); + } + } + + public DecisionOption(String name) { + this(name, (User) null, false); + } + + public DecisionOption() { + this("", (User) null, false); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DecisionOption) { + DecisionOption state = (DecisionOption) obj; + if (!state.name.equals(name)) { + return false; + } + return true; + } + return super.equals(obj); + } + + public Collection<User> getAssignees() { + return assignees; + } + + /** + * Sets the assigness but DOES NOT write to SMA. This method should NOT be called outside the StateMachineArtifact. + */ + public void setAssignees(Collection<User> assignees) { + this.assignees.clear(); + if (assignees != null) { + this.assignees.addAll(assignees); + } + } + + /** + * Sets the assignes but DOES NOT write to SMA. This method should NOT be called outside the StateMachineArtifact. + */ + public void setAssignee(User assignee) { + this.assignees.clear(); + if (assignee != null) { + this.assignees.add(assignee); + } + } + + public void addAssignee(User assignee) { + if (assignee != null) { + this.assignees.add(assignee); + } + } + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + public String toXml() throws OseeCoreException { + StringBuffer sb = new StringBuffer(name); + sb.append(";"); + for (User u : assignees) { + sb.append("<" + u.getUserId() + ">"); + } + sb.append(";"); + sb.append(followupRequired); + return sb.toString(); + } + + public Result setFromXml(String xml) { + Matcher m = Pattern.compile("^(.*?);(.*?);(.*)$").matcher(xml); + if (m.find()) { + String toState = m.group(2).toLowerCase(); + name = m.group(1); + if (name.equals("")) { + return new Result("Invalid name"); + } + if (toState.equals("followup")) { + followupRequired = true; + } else if (toState.equals("completed")) { + followupRequired = false; + } else { + return new Result("Invalid followup string \"" + m.group(2) + "\"\nShould be followup or completed"); + } + m = Pattern.compile("<(.*?)>").matcher(m.group(3)); + while (m.find()) { + try { + assignees.add(UserManager.getUserByUserId(m.group(1))); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + if (followupRequired && assignees.isEmpty()) { + return new Result("If followup is specified, must set assignees.\nShould be: <userid><userid>"); + } else if (!followupRequired && assignees.size() > 0) { + return new Result("If completed is specified, don't specify assigness. Leave blank.\n"); + } + } else { + return new Result( + "Can't unpack decision option data => " + xml + "\n\n" + "must be in format: \"Name;(followup|completed);<userid1><userid2>\"" + "where true if followup is required; false if not. If followup required, assignees will be userid1, userid2."); + } + return Result.TrueResult; + } + + /** + * @return the followupRequired + */ + public boolean isFollowupRequired() { + return followupRequired; + } + + /** + * @param followupRequired the followupRequired to set + */ + public void setFollowupRequired(boolean followupRequired) { + this.followupRequired = followupRequired; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewArtifact.java new file mode 100644 index 00000000000..a057752eb69 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewArtifact.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.util.Collection; +import org.eclipse.osee.ats.core.workflow.StateManager; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.IATSStateMachineArtifact; + +/** + * @author Donald G. Dunne + */ +public class DecisionReviewArtifact extends AbstractReviewArtifact implements IReviewArtifact, IATSStateMachineArtifact { + + public XDecisionOptions decisionOptions; + + public DecisionReviewArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + decisionOptions = new XDecisionOptions(this); + } + + @Override + public Collection<User> getImplementers() throws OseeCoreException { + return StateManager.getImplementersByState(this, DecisionReviewState.Decision); + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewManager.java new file mode 100644 index 00000000000..0a120d533c7 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewManager.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.review; + +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionOption; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * Methods in support of programatically transitioning the Decision Review Workflow through it's states. Only to be used + * for the DefaultReviewWorkflow of Prepare->Decision->ReWork->Complete + * + * @author Donald G. Dunne + */ +public final class DecisionReviewManager { + + private DecisionReviewManager() { + // private constructor + } + + /** + * Quickly transition to a state with minimal metrics and data entered. Should only be used for automated + * transitioning for things such as developmental testing and demos. + * + * @param user User to transition to OR null if should use user of current state + */ + public static Result transitionTo(DecisionReviewArtifact reviewArt, DecisionReviewState toState, User user, boolean popup, SkynetTransaction transaction) throws OseeCoreException { + Result result = Result.TrueResult; + // If in Prepare state, set data and transition to Decision + if (reviewArt.isInState(DecisionReviewState.Prepare)) { + result = setPrepareStateData(popup, reviewArt, 100, 3, .2); + if (result.isFalse()) { + return result; + } + result = + transitionToState(toState.getWorkPageType(), popup, DecisionReviewState.Decision, reviewArt, user, + transaction); + if (result.isFalse()) { + return result; + } + } + if (toState == DecisionReviewState.Decision) { + return Result.TrueResult; + } + + // If desired to transition to follow-up, then decision is false + boolean decision = toState != DecisionReviewState.Followup; + + result = setDecisionStateData(popup, reviewArt, decision, 100, .2); + if (result.isFalse()) { + return result; + } + + result = transitionToState(toState.getWorkPageType(), popup, toState, reviewArt, user, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + } + + public static Result setPrepareStateData(boolean popup, DecisionReviewArtifact reviewArt, int statePercentComplete, double estimateHours, double stateHoursSpent) throws OseeCoreException { + if (!reviewArt.isInState(DecisionReviewState.Prepare)) { + Result result = new Result("Action not in Prepare state"); + if (result.isFalse() && popup) { + return result; + } + } + reviewArt.setSoleAttributeValue(AtsAttributeTypes.EstimatedHours, estimateHours); + reviewArt.getStateMgr().updateMetrics(stateHoursSpent, statePercentComplete, true); + return Result.TrueResult; + } + + public static Result transitionToState(WorkPageType workPageType, boolean popup, IWorkPage toState, DecisionReviewArtifact reviewArt, User user, SkynetTransaction transaction) throws OseeCoreException { + TransitionManager transitionMgr = new TransitionManager(reviewArt); + Result result = + transitionMgr.transition(toState, + (user == null ? reviewArt.getStateMgr().getAssignees().iterator().next() : user), transaction, + TransitionOption.None); + return result; + } + + public static Result setDecisionStateData(boolean popup, DecisionReviewArtifact reviewArt, boolean decision, int statePercentComplete, double stateHoursSpent) throws OseeCoreException { + if (!reviewArt.isInState(DecisionReviewState.Decision)) { + Result result = new Result("Action not in Decision state"); + if (result.isFalse() && popup) { + return result; + } + } + reviewArt.setSoleAttributeValue(AtsAttributeTypes.Decision, decision ? "Yes" : "No"); + reviewArt.getStateMgr().updateMetrics(stateHoursSpent, statePercentComplete, true); + return Result.TrueResult; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewState.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewState.java new file mode 100644 index 00000000000..2426aea0400 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/DecisionReviewState.java @@ -0,0 +1,25 @@ +package org.eclipse.osee.ats.core.review; + +import java.util.List; +import org.eclipse.osee.framework.core.util.WorkPageAdapter; +import org.eclipse.osee.framework.core.util.WorkPageType; + +public class DecisionReviewState extends WorkPageAdapter { + public static DecisionReviewState Prepare = new DecisionReviewState("Prepare", WorkPageType.Working); + public static DecisionReviewState Decision = new DecisionReviewState("Decision", WorkPageType.Working); + public static DecisionReviewState Followup = new DecisionReviewState("Followup", WorkPageType.Working); + public static DecisionReviewState Completed = new DecisionReviewState("Completed", WorkPageType.Completed); + + private DecisionReviewState(String pageName, WorkPageType workPageType) { + super(DecisionReviewState.class, pageName, workPageType); + } + + public static DecisionReviewState valueOf(String pageName) { + return WorkPageAdapter.valueOfPage(DecisionReviewState.class, pageName); + } + + public static List<DecisionReviewState> values() { + return WorkPageAdapter.pages(DecisionReviewState.class); + } + +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/IReviewArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/IReviewArtifact.java new file mode 100644 index 00000000000..3fd417d7d25 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/IReviewArtifact.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import org.eclipse.osee.ats.core.review.defect.DefectManager; +import org.eclipse.osee.ats.core.review.role.UserRoleManager; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public interface IReviewArtifact { + + boolean isBlocking() throws OseeCoreException; + + DefectManager getDefectManager(); + + UserRoleManager getUserRoleManager(); + + Artifact getArtifact(); + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewArtifact.java new file mode 100644 index 00000000000..bf9d46376d0 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewArtifact.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.util.Collection; +import org.eclipse.osee.ats.core.review.defect.DefectManager; +import org.eclipse.osee.ats.core.review.role.UserRole; +import org.eclipse.osee.ats.core.workflow.StateManager; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.IATSStateMachineArtifact; + +/** + * @author Donald G. Dunne + */ +public class PeerToPeerReviewArtifact extends AbstractReviewArtifact implements IReviewArtifact, IATSStateMachineArtifact { + + public PeerToPeerReviewArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + defectManager = new DefectManager(this); + } + + @Override + public Collection<User> getImplementers() throws OseeCoreException { + Collection<User> users = StateManager.getImplementersByState(this, PeerToPeerReviewState.Review); + for (UserRole role : userRoleManager.getUserRoles()) { + users.add(role.getUser()); + } + return users; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewManager.java new file mode 100644 index 00000000000..62ac2e9353a --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewManager.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.review; + +import java.util.Collection; +import org.eclipse.osee.ats.core.review.defect.DefectItem; +import org.eclipse.osee.ats.core.review.role.UserRole; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionOption; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * Methods in support of programatically transitioning the Peer Review Workflow through it's states. Only to be used for + * the DefaultReviewWorkflow of Prepare->Review->Complete + * + * @author Donald G. Dunne + */ +public final class PeerToPeerReviewManager { + + public static String getDefaultReviewTitle(TeamWorkFlowArtifact teamArt) { + return "Review \"" + teamArt.getArtifactTypeName() + "\" titled \"" + teamArt.getName() + "\""; + } + + private PeerToPeerReviewManager() { + // private constructor + } + + /** + * Quickly transition to a state with minimal metrics and data entered. Should only be used for automated transition + * for things such as developmental testing and demos. + * + * @param user User to transition to OR null if should use user of current state + */ + public static Result transitionTo(PeerToPeerReviewArtifact reviewArt, PeerToPeerReviewState toState, Collection<UserRole> roles, Collection<DefectItem> defects, User user, boolean popup, SkynetTransaction transaction) throws OseeCoreException { + Result result = setPrepareStateData(popup, reviewArt, roles, "DoThis.java", 100, .2, transaction); + if (result.isFalse()) { + return result; + } + result = + transitionToState(PeerToPeerReviewState.Review.getWorkPageType(), popup, reviewArt, + PeerToPeerReviewState.Review, transaction); + if (result.isFalse()) { + return result; + } + if (toState == PeerToPeerReviewState.Review) { + return Result.TrueResult; + } + + result = setReviewStateData(popup, reviewArt, roles, defects, 100, .2, transaction); + if (result.isFalse()) { + return result; + } + + result = + transitionToState(PeerToPeerReviewState.Completed.getWorkPageType(), popup, reviewArt, + PeerToPeerReviewState.Completed, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + } + + private static Result transitionToState(WorkPageType workPageType, boolean popup, PeerToPeerReviewArtifact reviewArt, IWorkPage toState, SkynetTransaction transaction) throws OseeCoreException { + TransitionManager transitionMgr = new TransitionManager(reviewArt); + Result result = + transitionMgr.transition(toState, reviewArt.getStateMgr().getAssignees().iterator().next(), transaction, + TransitionOption.None); + return result; + } + + public static Result setPrepareStateData(boolean popup, PeerToPeerReviewArtifact reviewArt, Collection<UserRole> roles, String reviewMaterials, int statePercentComplete, double stateHoursSpent, SkynetTransaction transaction) throws OseeCoreException { + if (!reviewArt.isInState(PeerToPeerReviewState.Prepare)) { + Result result = new Result("Action not in Prepare state"); + if (result.isFalse() && popup) { + return result; + } + + } + if (roles != null) { + for (UserRole role : roles) { + reviewArt.getUserRoleManager().addOrUpdateUserRole(role, false, transaction); + } + } + reviewArt.setSoleAttributeValue(AtsAttributeTypes.Location, reviewMaterials); + reviewArt.getStateMgr().updateMetrics(stateHoursSpent, statePercentComplete, true); + return Result.TrueResult; + } + + public static Result setReviewStateData(boolean popup, PeerToPeerReviewArtifact reviewArt, Collection<UserRole> roles, Collection<DefectItem> defects, int statePercentComplete, double stateHoursSpent, SkynetTransaction transaction) throws OseeCoreException { + if (roles != null) { + for (UserRole role : roles) { + reviewArt.getUserRoleManager().addOrUpdateUserRole(role, false, transaction); + } + } + if (defects != null) { + for (DefectItem defect : defects) { + reviewArt.getDefectManager().addOrUpdateDefectItem(defect, false, transaction); + } + } + reviewArt.getStateMgr().updateMetrics(stateHoursSpent, statePercentComplete, true); + return Result.TrueResult; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewState.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewState.java new file mode 100644 index 00000000000..cc99c85b3d3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/PeerToPeerReviewState.java @@ -0,0 +1,25 @@ +package org.eclipse.osee.ats.core.review; + +import java.util.List; +import org.eclipse.osee.framework.core.util.WorkPageAdapter; +import org.eclipse.osee.framework.core.util.WorkPageType; + +public class PeerToPeerReviewState extends WorkPageAdapter { + public static PeerToPeerReviewState Prepare = new PeerToPeerReviewState("Prepare", WorkPageType.Working); + public static PeerToPeerReviewState Review = new PeerToPeerReviewState("Review", WorkPageType.Working); + public static PeerToPeerReviewState Meeting = new PeerToPeerReviewState("Meeting", WorkPageType.Working); + public static PeerToPeerReviewState Completed = new PeerToPeerReviewState("Completed", WorkPageType.Completed); + + private PeerToPeerReviewState(String pageName, WorkPageType workPageType) { + super(PeerToPeerReviewState.class, pageName, workPageType); + } + + public static PeerToPeerReviewState valueOf(String pageName) { + return WorkPageAdapter.valueOfPage(PeerToPeerReviewState.class, pageName); + } + + public static List<PeerToPeerReviewState> values() { + return WorkPageAdapter.pages(PeerToPeerReviewState.class); + } + +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewFormalType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewFormalType.java new file mode 100644 index 00000000000..16658d436ca --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewFormalType.java @@ -0,0 +1,6 @@ +package org.eclipse.osee.ats.core.review; + +public enum ReviewFormalType { + InFormal, + Formal +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewManager.java new file mode 100644 index 00000000000..42a6eabb790 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/ReviewManager.java @@ -0,0 +1,350 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.workdef.DecisionReviewOption; +import org.eclipse.osee.ats.core.workdef.ReviewBlockType; +import org.eclipse.osee.ats.core.workdef.RuleDefinitionOption; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workflow.HoursSpentUtil; +import org.eclipse.osee.ats.core.workflow.PercentCompleteTotalUtil; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionOption; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactTypeManager; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; +import org.eclipse.osee.framework.skynet.core.utility.UsersByIds; + +/** + * @author Donald G. Dunne + */ +public class ReviewManager { + + private final static String VALIDATE_REVIEW_TITLE = "Is the resolution of this Action valid?"; + + public ReviewManager() { + super(); + } + + public static boolean isValidatePage(StateDefinition stateDefinition) { + if (stateDefinition.hasRule(RuleDefinitionOption.AddDecisionValidateBlockingReview)) { + return true; + } + if (stateDefinition.hasRule(RuleDefinitionOption.AddDecisionValidateNonBlockingReview)) { + return true; + } + return false; + } + + /** + * Create a new decision review configured and transitioned to handle action validation + * + * @param force will force the creation of the review without checking that a review should be created + */ + public static DecisionReviewArtifact createValidateReview(TeamWorkFlowArtifact teamArt, boolean force, Date createdDate, User createdBy, SkynetTransaction transaction) throws OseeCoreException { + // If not validate page, don't do anything + if (!force && !isValidatePage(teamArt.getStateDefinition())) { + return null; + } + // If validate review already created for this state, return + if (!force && getReviewsFromCurrentState(teamArt).size() > 0) { + for (AbstractReviewArtifact rev : getReviewsFromCurrentState(teamArt)) { + if (rev.getName().equals(VALIDATE_REVIEW_TITLE)) { + return null; + } + } + } + // Create validate review + try { + + DecisionReviewArtifact decRev = + ReviewManager.createNewDecisionReview( + teamArt, + isValidateReviewBlocking(teamArt.getStateDefinition()) ? ReviewBlockType.Transition : ReviewBlockType.None, + true, createdDate, createdBy); + decRev.setName(VALIDATE_REVIEW_TITLE); + decRev.setSoleAttributeValue(AtsAttributeTypes.DecisionReviewOptions, + "No;Followup;" + getValidateReviewFollowupUsersStr(teamArt) + "\n" + "Yes;Completed;"); + + TransitionManager transitionMgr = new TransitionManager(decRev); + transitionMgr.transition(DecisionReviewState.Decision, teamArt.getCreatedBy(), transaction, + TransitionOption.Persist); + + return decRev; + + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + } + return null; + } + + public static boolean isValidateReviewBlocking(StateDefinition stateDefinition) { + return stateDefinition.hasRule(RuleDefinitionOption.AddDecisionValidateBlockingReview); + } + + public static DecisionReviewArtifact createNewDecisionReview(TeamWorkFlowArtifact teamArt, String reviewTitle, String description, String againstState, ReviewBlockType reviewBlockType, Collection<DecisionReviewOption> options, Collection<User> assignees, Date createdDate, User createdBy, SkynetTransaction transaction) throws OseeCoreException { + DecisionReviewArtifact decRev = + ReviewManager.createNewDecisionReview(teamArt, reviewBlockType, reviewTitle, againstState, description, + options, assignees, createdDate, createdBy); + return decRev; + } + + public static DecisionReviewArtifact createNewDecisionReviewAndTransitionToDecision(TeamWorkFlowArtifact teamArt, String reviewTitle, String description, String againstState, ReviewBlockType reviewBlockType, Collection<DecisionReviewOption> options, Collection<User> assignees, Date createdDate, User createdBy, SkynetTransaction transaction) throws OseeCoreException { + DecisionReviewArtifact decRev = + ReviewManager.createNewDecisionReview(teamArt, reviewBlockType, reviewTitle, againstState, description, + options, assignees, createdDate, createdBy); + decRev.persist(transaction); + + TransitionManager transitionMgr = new TransitionManager(decRev); + Result result = + transitionMgr.transition(DecisionReviewState.Decision, assignees, transaction, TransitionOption.Persist, + TransitionOption.OverrideAssigneeCheck); + if (result.isFalse()) { + throw new OseeStateException("Error auto-transitioning review %s to Decision state", decRev.toStringWithId()); + } + return decRev; + } + + public static PeerToPeerReviewArtifact createNewPeerToPeerReview(TeamWorkFlowArtifact teamArt, String reviewTitle, String againstState, SkynetTransaction transaction) throws OseeCoreException { + return createNewPeerToPeerReview(teamArt, reviewTitle, againstState, new Date(), UserManager.getUser(), + transaction); + } + + public static PeerToPeerReviewArtifact createNewPeerToPeerReview(TeamWorkFlowArtifact teamArt, String reviewTitle, String againstState, Date createdDate, User createdBy, SkynetTransaction transaction) throws OseeCoreException { + PeerToPeerReviewArtifact peerToPeerRev = + (PeerToPeerReviewArtifact) ArtifactTypeManager.addArtifact(AtsArtifactTypes.PeerToPeerReview, + AtsUtilCore.getAtsBranch(), reviewTitle == null ? "Peer to Peer Review" : reviewTitle); + // Initialize state machine + peerToPeerRev.initializeNewStateMachine(null, new Date(), createdBy); + + if (teamArt != null) { + teamArt.addRelation(AtsRelationTypes.TeamWorkflowToReview_Review, peerToPeerRev); + if (againstState != null) { + peerToPeerRev.setSoleAttributeValue(AtsAttributeTypes.RelatedToState, againstState); + } + } + peerToPeerRev.setSoleAttributeValue(AtsAttributeTypes.ReviewBlocks, ReviewBlockType.None.name()); + peerToPeerRev.setSoleAttributeValue(AtsAttributeTypes.ReviewFormalType, ReviewFormalType.InFormal.name()); + peerToPeerRev.persist(transaction); + return peerToPeerRev; + } + + /** + * Return Remain Hours for all reviews + */ + public static double getRemainHours(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + double hours = 0; + for (AbstractReviewArtifact reviewArt : getReviews(teamArt)) { + hours += reviewArt.getRemainHoursFromArtifact(); + } + return hours; + + } + + /** + * Return Estimated Review Hours of "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + */ + public static double getEstimatedHours(TeamWorkFlowArtifact teamArt, IWorkPage relatedToState) throws OseeCoreException { + double hours = 0; + for (AbstractReviewArtifact revArt : getReviews(teamArt, relatedToState)) { + hours += revArt.getEstimatedHoursTotal(); + } + return hours; + } + + /** + * Return Estimated Hours for all reviews + */ + public static double getEstimatedHours(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + double hours = 0; + for (AbstractReviewArtifact revArt : getReviews(teamArt)) { + hours += revArt.getEstimatedHoursTotal(); + } + return hours; + + } + + public static String getValidateReviewFollowupUsersStr(TeamWorkFlowArtifact teamArt) { + try { + return UsersByIds.getStorageString(getValidateReviewFollowupUsers(teamArt)); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return ex.getLocalizedMessage(); + } + } + + public static Collection<User> getValidateReviewFollowupUsers(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + Collection<User> users = teamArt.getStateMgr().getAssignees(TeamState.Implement); + if (users.size() > 0) { + return users; + } + + // Else if Team Workflow , return it to the leads of this team + return teamArt.getTeamDefinition().getLeads(); + + } + + public static Collection<AbstractReviewArtifact> getReviews(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + return teamArt.getRelatedArtifacts(AtsRelationTypes.TeamWorkflowToReview_Review, AbstractReviewArtifact.class); + } + + public static Collection<AbstractReviewArtifact> getReviewsFromCurrentState(TeamWorkFlowArtifact teamArt) throws OseeCoreException { + return getReviews(teamArt, teamArt.getStateMgr().getCurrentState()); + } + + public static Collection<AbstractReviewArtifact> getReviews(TeamWorkFlowArtifact teamArt, IWorkPage state) throws OseeCoreException { + Set<AbstractReviewArtifact> arts = new HashSet<AbstractReviewArtifact>(); + for (AbstractReviewArtifact revArt : getReviews(teamArt)) { + if (revArt.getSoleAttributeValue(AtsAttributeTypes.RelatedToState, "").equals(state.getPageName())) { + arts.add(revArt); + } + } + return arts; + } + + public static boolean hasReviews(TeamWorkFlowArtifact teamArt) { + return teamArt.getRelatedArtifactsCount(AtsRelationTypes.TeamWorkflowToReview_Review) > 0; + } + + public static Result areReviewsComplete(TeamWorkFlowArtifact teamArt) { + return areReviewsComplete(teamArt, true); + } + + public static Result areReviewsComplete(TeamWorkFlowArtifact teamArt, boolean popup) { + try { + for (AbstractReviewArtifact reviewArt : getReviews(teamArt)) { + if (!reviewArt.isCompleted() && reviewArt.isCancelled()) { + return new Result("Not Complete"); + } + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return Result.TrueResult; + } + + /** + * Return Hours Spent for Reviews of "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + */ + public static double getHoursSpent(TeamWorkFlowArtifact teamArt, IWorkPage relatedToState) throws OseeCoreException { + double spent = 0; + for (AbstractReviewArtifact reviewArt : getReviews(teamArt, relatedToState)) { + spent += HoursSpentUtil.getHoursSpentTotal(reviewArt); + } + return spent; + } + + /** + * Return Total Percent Complete / # Reviews for "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + */ + public static int getPercentComplete(TeamWorkFlowArtifact teamArt, IWorkPage relatedToState) throws OseeCoreException { + int spent = 0; + Collection<AbstractReviewArtifact> reviewArts = getReviews(teamArt, relatedToState); + for (AbstractReviewArtifact reviewArt : reviewArts) { + spent += PercentCompleteTotalUtil.getPercentCompleteTotal(reviewArt); + } + if (spent == 0) { + return 0; + } + return spent / reviewArts.size(); + } + + public static DecisionReviewArtifact createNewDecisionReview(TeamWorkFlowArtifact teamArt, ReviewBlockType reviewBlockType, boolean againstCurrentState, Date createdDate, User createdBy) throws OseeCoreException { + return createNewDecisionReview(teamArt, reviewBlockType, + "Should we do this? Yes will require followup, No will not", + againstCurrentState ? teamArt.getStateMgr().getCurrentStateName() : null, + "Enter description of the decision, if any", getDefaultDecisionReviewOptions(), null, createdDate, createdBy); + } + + public static List<DecisionReviewOption> getDefaultDecisionReviewOptions() throws OseeCoreException { + List<DecisionReviewOption> options = new ArrayList<DecisionReviewOption>(); + options.add(new DecisionReviewOption("Yes", true, Arrays.asList(UserManager.getUser().getUserId()))); + options.add(new DecisionReviewOption("No", false, null)); + return options; + } + + public static String getDecisionReviewOptionsString(Collection<DecisionReviewOption> options) { + StringBuffer sb = new StringBuffer(); + for (DecisionReviewOption opt : options) { + sb.append(opt.getName()); + sb.append(";"); + sb.append(opt.isFollowupRequired() ? "Followup" : "Completed"); + sb.append(";"); + for (String userId : opt.getUserIds()) { + sb.append("<" + userId + ">"); + } + sb.append("\n"); + } + return sb.toString(); + } + + public static DecisionReviewArtifact createNewDecisionReview(TeamWorkFlowArtifact teamArt, ReviewBlockType reviewBlockType, String title, String relatedToState, String description, Collection<DecisionReviewOption> options, Collection<User> assignees, Date createdDate, User createdBy) throws OseeCoreException { + DecisionReviewArtifact decRev = + (DecisionReviewArtifact) ArtifactTypeManager.addArtifact(AtsArtifactTypes.DecisionReview, + AtsUtilCore.getAtsBranch(), title); + + // Initialize state machine + decRev.initializeNewStateMachine(assignees, createdDate, createdBy); + + if (teamArt != null) { + teamArt.addRelation(AtsRelationTypes.TeamWorkflowToReview_Review, decRev); + } + if (Strings.isValid(relatedToState)) { + decRev.setSoleAttributeValue(AtsAttributeTypes.RelatedToState, relatedToState); + } + if (Strings.isValid(description)) { + decRev.setSoleAttributeValue(AtsAttributeTypes.Description, description); + } + decRev.setSoleAttributeValue(AtsAttributeTypes.DecisionReviewOptions, getDecisionReviewOptionsString(options)); + if (reviewBlockType != null) { + decRev.setSoleAttributeFromString(AtsAttributeTypes.ReviewBlocks, reviewBlockType.name()); + } + + return decRev; + } + + public static AbstractReviewArtifact cast(Artifact artifact) { + if (artifact instanceof AbstractReviewArtifact) { + return (AbstractReviewArtifact) artifact; + } + return null; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/XDecisionOptions.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/XDecisionOptions.java new file mode 100644 index 00000000000..d64fe230bca --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/XDecisionOptions.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.framework.core.data.IAttributeType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.logging.OseeLog; + +/** + * @author Donald G. Dunne + */ +public class XDecisionOptions { + + private final WeakReference<AbstractWorkflowArtifact> smaRef; + private final IAttributeType attributeType; + + public XDecisionOptions(AbstractWorkflowArtifact sma) { + this.smaRef = new WeakReference<AbstractWorkflowArtifact>(sma); + this.attributeType = AtsAttributeTypes.DecisionReviewOptions; + } + + public IAttributeType getAttributeType() { + return attributeType; + } + + public Set<DecisionOption> getDecisionOptions() throws OseeCoreException { + String decString = getSma().getSoleAttributeValue(getAttributeType(), ""); + return getDecisionOptions(decString); + } + + public AbstractWorkflowArtifact getSma() throws OseeStateException { + if (smaRef.get() == null) { + throw new OseeStateException("Artifact has been garbage collected"); + } + return smaRef.get(); + } + + public static Set<DecisionOption> getDecisionOptions(String decisionOptions) { + Set<DecisionOption> decOptions = new HashSet<DecisionOption>(); + for (String decsionOpt : decisionOptions.split("[\n\r]+")) { + DecisionOption state = new DecisionOption(); + Result result = state.setFromXml(decsionOpt); + if (result.isFalse()) { + OseeLog.log(Activator.class, Level.SEVERE, result.getText()); + } else { + decOptions.add(state); + } + } + return decOptions; + } + + public DecisionOption getDecisionOption(String name) throws OseeCoreException { + for (DecisionOption opt : getDecisionOptions()) { + if (opt.getName().equals(name)) { + return opt; + } + } + return null; + } + + public Result validateDecisionOptions() throws OseeCoreException { + return validateDecisionOptions(getSma().getSoleAttributeValue(getAttributeType(), "")); + } + + public static Result validateDecisionOptions(String decisionOptions) { + for (String decsionOpt : decisionOptions.split("[\n\r]+")) { + DecisionOption state = new DecisionOption(); + Result result = state.setFromXml(decsionOpt); + if (result.isFalse()) { + return new Result("Invalid Decision Option \"" + decsionOpt + "\" " + result.getText()); + } + } + return Result.TrueResult; + } + + public String toXml(Set<DecisionOption> opts) throws OseeCoreException { + StringBuffer sb = new StringBuffer(); + for (DecisionOption opt : opts) { + sb.append(opt.toXml()); + sb.append("\n"); + } + return sb.toString().replaceFirst("\n$", ""); + } + + public void setDecisionOptions(String decisionOptions) throws OseeCoreException { + getSma().setSoleAttributeValue(getAttributeType(), toXml(getDecisionOptions(decisionOptions))); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectItem.java new file mode 100644 index 00000000000..9e458efc27f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectItem.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review.defect; + +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.jdk.core.util.GUID; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; + +/** + * @author Donald G. Dunne + */ +public class DefectItem { + + private Date date = new Date(); + private String description = ""; + private String location = ""; + private String resolution = ""; + private User user; + private String guid = GUID.create(); + private Severity severity = Severity.None; + private Disposition disposition = Disposition.None; + private InjectionActivity injectionActivity = InjectionActivity.None; + private boolean closed = false; + public static enum Severity { + None, + Major, + Minor, + Issue; + public static Collection<String> strValues() { + Set<String> values = new HashSet<String>(); + for (Enum<Severity> e : values()) { + values.add(e.name()); + } + return values; + } + + }; + + public DefectItem() throws OseeCoreException { + user = UserManager.getUser(); + } + + public DefectItem(User user, Severity severity, Disposition disposition, InjectionActivity injectionActivity, String description, String resolution, String location, Date date) { + this.user = user; + if (severity != null) { + this.severity = severity; + } + if (disposition != null) { + this.disposition = disposition; + } + if (injectionActivity != null) { + this.injectionActivity = injectionActivity; + } + if (description != null) { + this.description = description; + } + if (resolution != null) { + this.resolution = resolution; + } + if (location != null) { + this.location = location; + } + if (date != null) { + this.date = date; + } + } + + public DefectItem(String xml) throws OseeCoreException { + fromXml(xml); + } + + public void update(DefectItem dItem) throws OseeCoreException { + fromXml(dItem.toXml()); + } + + public static enum Disposition { + None, + Accept, + Reject, + Duplicate; + public static Collection<String> strValues() { + Set<String> values = new HashSet<String>(); + for (Enum<Disposition> e : values()) { + values.add(e.name()); + } + return values; + } + + }; + public static enum InjectionActivity { + None, + Planning, + System_Level_Requirements, + System_Design, + Software_Requirements, + Software_Design, + Code, + Test, + Other; + public static Collection<String> strValues() { + Set<String> values = new HashSet<String>(); + for (Enum<InjectionActivity> e : values()) { + values.add(e.name()); + } + return values; + } + }; + + public String getDate(String pattern) { + if (pattern != null) { + return new SimpleDateFormat(pattern).format(date); + } + return date.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DefectItem) { + DefectItem di = (DefectItem) obj; + return di.guid.equals(getGuid()); + } + return false; + } + + @Override + public int hashCode() { + return guid.hashCode(); + } + + public String toXml() throws OseeCoreException { + return "<severity>" + severity.name() + "</severity><disposition>" + disposition.name() + + // + "</disposition><injectionActivity>" + injectionActivity.name() + "</injectionActivity><date>" + date.getTime() + + // + "</date><user>" + user.getUserId() + "</user><description>" + description + "</description><location>" + location + + // + "</location><resolution>" + resolution + "</resolution><closed>" + closed + "</closed><guid>" + guid + "</guid>"; + } + + private void fromXml(String xml) throws OseeCoreException { + this.severity = Severity.valueOf(AXml.getTagData(xml, "severity")); + this.disposition = Disposition.valueOf(AXml.getTagData(xml, "disposition")); + this.injectionActivity = InjectionActivity.valueOf(AXml.getTagData(xml, "injectionActivity")); + Date date = new Date(); + date.setTime(new Long(AXml.getTagData(xml, "date"))); + this.date = date; + this.user = UserManager.getUserByUserId(AXml.getTagData(xml, "user")); + this.description = AXml.getTagData(xml, "description"); + this.location = AXml.getTagData(xml, "location"); + this.resolution = AXml.getTagData(xml, "resolution"); + this.closed = AXml.getTagBooleanData(xml, "closed"); + this.guid = AXml.getTagData(xml, "guid"); + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + @Override + public String toString() { + return severity + " - " + disposition + " - " + injectionActivity + " - " + user + " on " + DateUtil.getMMDDYYHHMM(date) + "\n"; + } + + public User getUser() { + return user; + } + + public String toHTML(String labelFont) { + return "DEFECT (" + severity + "): " + description + " (" + user.getName() + ")"; + } + + /** + * @param user The user to set. + */ + public void setUser(User user) { + this.user = user; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getResolution() { + return resolution; + } + + public void setResolution(String resolution) { + this.resolution = resolution; + } + + public Severity getSeverity() { + return severity; + } + + public void setSeverity(Severity severity) { + this.severity = severity; + } + + public Disposition getDisposition() { + return disposition; + } + + public void setDisposition(Disposition disposition) { + this.disposition = disposition; + } + + public InjectionActivity getInjectionActivity() { + return injectionActivity; + } + + public void setInjectionActivity(InjectionActivity injectionActivity) { + this.injectionActivity = injectionActivity; + } + + public boolean isClosed() { + return closed; + } + + public void setClosed(boolean closed) { + this.closed = closed; + } + + /** + * @return the guid + */ + public String getGuid() { + return guid; + } + + /** + * @param guid the guid to set + */ + public void setGuid(String guid) { + this.guid = guid; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectManager.java new file mode 100644 index 00000000000..ce92b2cc6e8 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/defect/DefectManager.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review.defect; + +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.defect.DefectItem.Severity; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.data.IAttributeType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.jdk.core.util.AHTML; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.Attribute; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public class DefectManager { + + private final WeakReference<Artifact> artifactRef; + private boolean enabled = true; + private final static String DEFECT_ITEM_TAG = "Item"; + private static final IAttributeType REVIEW_STORAGE_TYPE = AtsAttributeTypes.ReviewDefect; + + private final Matcher defectMatcher = java.util.regex.Pattern.compile( + "<" + DEFECT_ITEM_TAG + ">(.*?)</" + DEFECT_ITEM_TAG + ">", Pattern.DOTALL | Pattern.MULTILINE).matcher(""); + + public DefectManager(Artifact artifact) { + this.artifactRef = new WeakReference<Artifact>(artifact); + } + + public Artifact getArtifact() throws OseeStateException { + if (artifactRef.get() == null) { + throw new OseeStateException("Artifact has been garbage collected"); + } + return artifactRef.get(); + } + + public String getHtml() throws OseeCoreException { + if (getDefectItems().isEmpty()) { + return ""; + } + StringBuffer sb = new StringBuffer(); + sb.append(AHTML.addSpace(1) + AHTML.getLabelStr(AHTML.LABEL_FONT, "Defects")); + sb.append(getTable()); + return sb.toString(); + } + + public Set<DefectItem> getDefectItems() throws OseeCoreException { + Set<DefectItem> defectItems = new HashSet<DefectItem>(); + for (String xml : getArtifact().getAttributesToStringList(REVIEW_STORAGE_TYPE)) { + defectMatcher.reset(xml); + while (defectMatcher.find()) { + DefectItem item = new DefectItem(defectMatcher.group()); + defectItems.add(item); + } + } + return defectItems; + } + + public int getNumMajor() throws OseeCoreException { + int x = 0; + for (DefectItem dItem : getDefectItems()) { + if (dItem.getSeverity() == Severity.Major) { + x++; + } + } + return x; + } + + public int getNumMinor() throws OseeCoreException { + int x = 0; + for (DefectItem dItem : getDefectItems()) { + if (dItem.getSeverity() == Severity.Minor) { + x++; + } + } + return x; + } + + public int getNumIssues() throws OseeCoreException { + int x = 0; + for (DefectItem dItem : getDefectItems()) { + if (dItem.getSeverity() == Severity.Issue) { + x++; + } + } + return x; + } + + private void saveDefectItems(Set<DefectItem> defectItems, boolean persist, SkynetTransaction transaction) { + try { + // Change existing ones + for (Attribute<?> attr : getArtifact().getAttributes(REVIEW_STORAGE_TYPE)) { + DefectItem dbPromoteItem = new DefectItem((String) attr.getValue()); + for (DefectItem pItem : defectItems) { + if (pItem.equals(dbPromoteItem)) { + attr.setFromString(AXml.addTagData(DEFECT_ITEM_TAG, pItem.toXml())); + } + } + } + Set<DefectItem> dbPromoteItems = getDefectItems(); + // Remove deleted ones; items in dbPromoteItems that are not in promoteItems + for (DefectItem delPromoteItem : org.eclipse.osee.framework.jdk.core.util.Collections.setComplement( + dbPromoteItems, defectItems)) { + for (Attribute<?> attr : getArtifact().getAttributes(REVIEW_STORAGE_TYPE)) { + DefectItem dbPromoteItem = new DefectItem((String) attr.getValue()); + if (dbPromoteItem.equals(delPromoteItem)) { + attr.delete(); + } + } + } + // Add new ones: items in promoteItems that are not in dbPromoteItems + for (DefectItem newPromoteItem : org.eclipse.osee.framework.jdk.core.util.Collections.setComplement( + defectItems, dbPromoteItems)) { + getArtifact().addAttributeFromString(REVIEW_STORAGE_TYPE, + AXml.addTagData(DEFECT_ITEM_TAG, newPromoteItem.toXml())); + } + if (persist) { + getArtifact().persist(transaction); + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't create ats review defect document", ex); + } + } + + public void addOrUpdateDefectItem(DefectItem defectItem, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + Set<DefectItem> defectItems = getDefectItems(); + boolean found = false; + for (DefectItem dItem : defectItems) { + if (defectItem.equals(dItem)) { + dItem.update(defectItem); + found = true; + } + } + if (!found) { + defectItems.add(defectItem); + } + saveDefectItems(defectItems, persist, transaction); + } + + public void removeDefectItem(DefectItem defectItem, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + Set<DefectItem> defectItems = getDefectItems(); + defectItems.remove(defectItem); + saveDefectItems(defectItems, persist, transaction); + } + + public void addDefectItem(String description, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + DefectItem item = new DefectItem(); + item.setDescription(description); + addOrUpdateDefectItem(item, persist, transaction); + } + + public String getTable() throws OseeCoreException { + StringBuilder builder = new StringBuilder(); + builder.append("<TABLE BORDER=\"1\" cellspacing=\"1\" cellpadding=\"3%\" width=\"100%\"><THEAD><TR><TH>Severity</TH>" + "<TH>Disposition</TH><TH>Injection</TH><TH>User</TH><TH>Date</TH><TH>Description</TH><TH>Location</TH>" + "<TH>Resolution</TH><TH>Guid</TH><TH>Completed</TH></THEAD></TR>"); + for (DefectItem item : getDefectItems()) { + User user = item.getUser(); + builder.append("<TR>"); + builder.append("<TD>" + item.getSeverity() + "</TD>"); + builder.append("<TD>" + item.getDisposition() + "</TD>"); + builder.append("<TD>" + item.getInjectionActivity() + "</TD>"); + if (user != null && user.equals(UserManager.getUser())) { + builder.append("<TD bgcolor=\"#CCCCCC\">" + user.getName() + "</TD>"); + } else { + builder.append("<TD>NONE</TD>"); + } + builder.append("<TD>" + DateUtil.getMMDDYYHHMM(item.getDate()) + "</TD>"); + builder.append("<TD>" + item.getDescription() + "</TD>"); + builder.append("<TD>" + item.getLocation() + "</TD>"); + builder.append("<TD>" + item.getResolution() + "</TD>"); + builder.append("<TD>" + item.getGuid() + "</TD>"); + builder.append("<TD>" + item.isClosed() + "</TD>"); + builder.append("</TR>"); + + } + builder.append("</TABLE>"); + return builder.toString(); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/Role.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/Role.java new file mode 100644 index 00000000000..1c822efa70f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/Role.java @@ -0,0 +1,18 @@ +package org.eclipse.osee.ats.core.review.role; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public enum Role { + Moderator, + Reviewer, + Author; + public static Collection<String> strValues() { + Set<String> values = new HashSet<String>(); + for (Enum<Role> e : values()) { + values.add(e.name()); + } + return values; + } +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRole.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRole.java new file mode 100644 index 00000000000..46377fde16e --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRole.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review.role; + +import java.text.NumberFormat; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.eclipse.osee.framework.jdk.core.util.GUID; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; + +/** + * @author Donald G. Dunne + */ +public class UserRole { + + private Role role = Role.Reviewer; + private User user; + private Double hoursSpent = null; + private String guid = GUID.create(); + private Boolean completed = false; + + public UserRole() throws OseeCoreException { + this(Role.Reviewer, UserManager.getUser(), null, false); + } + + public UserRole(Role role, User user) { + this(role, user, 0.0, false); + } + + public UserRole(Role role, User user, Double hoursSpent, Boolean completed) { + this.role = role; + this.user = user; + this.hoursSpent = hoursSpent; + this.completed = completed; + } + + public UserRole(String xml) { + fromXml(xml); + } + + public void update(UserRole dItem) throws OseeCoreException { + fromXml(dItem.toXml()); + } + + public String toXml() throws OseeCoreException { + StringBuffer sb = new StringBuffer(); + sb.append(AXml.addTagData("role", role.name())); + sb.append(AXml.addTagData("userId", user.getUserId())); + sb.append(AXml.addTagData("hoursSpent", hoursSpent == null ? "" : String.valueOf(hoursSpent))); + sb.append(AXml.addTagData("completed", String.valueOf(completed))); + sb.append(AXml.addTagData("guid", guid)); + return sb.toString(); + } + + public void fromXml(String xml) { + try { + this.role = Role.valueOf(AXml.getTagData(xml, "role")); + this.user = UserManager.getUserByUserId(AXml.getTagData(xml, "userId")); + String hoursSpent = AXml.getTagData(xml, "hoursSpent"); + if (Strings.isValid(hoursSpent)) { + this.hoursSpent = NumberFormat.getInstance().parse(hoursSpent).doubleValue(); + } else { + this.hoursSpent = null; + } + String completedStr = AXml.getTagData(xml, "completed"); + if (Strings.isValid(completedStr)) { + this.completed = completedStr.equals("true"); + } else { + this.completed = false; + } + this.guid = AXml.getTagData(xml, "guid"); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof UserRole) { + UserRole userRole = (UserRole) obj; + return userRole.getGuid().equals(getGuid()); + } + return false; + } + + @Override + public int hashCode() { + return getGuid().hashCode(); + } + + @Override + public String toString() { + return role + " - " + user + " - " + hoursSpent + " - " + (completed ? "Completed" : "InWork"); + } + + /** + * @return the role + */ + public Role getRole() { + return role; + } + + /** + * @param role the role to set + */ + public void setRole(Role role) { + this.role = role; + } + + /** + * @return the user + */ + public User getUser() { + return user; + } + + /** + * @param user the user to set + */ + public void setUser(User user) { + this.user = user; + } + + /** + * @return the hoursSpent + */ + public Double getHoursSpent() { + return hoursSpent; + } + + public String getHoursSpentStr() { + return hoursSpent == null ? "" : AtsUtilCore.doubleToI18nString(hoursSpent, true); + } + + /** + * @param hoursSpent the hoursSpent to set + */ + public void setHoursSpent(Double hoursSpent) { + this.hoursSpent = hoursSpent; + } + + /** + * @return the guid + */ + public String getGuid() { + return guid; + } + + /** + * @param guid the guid to set + */ + public void setGuid(String guid) { + this.guid = guid; + } + + /** + * @return the completed + */ + public boolean isCompleted() { + return completed; + } + + /** + * @param completed the completed to set + */ + public void setCompleted(boolean completed) { + this.completed = completed; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleError.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleError.java new file mode 100644 index 00000000000..8a6247f3226 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleError.java @@ -0,0 +1,33 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.review.role; + +/** + * @author Donald G. Dunne + */ +public enum UserRoleError { + + None(""), + OneRoleEntryRequired("At least one role entry is required."), + ExceptionValidatingRoles("Exception validating roles. See log for details."), + MustHaveAtLeastOneAuthor("Must have at least one Author"), + MustHaveAtLeastOneReviewer("Must have at least one Reviewer"), + HoursSpentMustBeEnteredForEachRole("Hours spent must be entered for each role."); + + private final String error; + + private UserRoleError(String error) { + this.error = error; + } + + public String getError() { + return error; + } + + public boolean isOK() { + return this == None; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleManager.java new file mode 100644 index 00000000000..4805afd407a --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleManager.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.review.role; + +import java.lang.ref.WeakReference; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.AbstractReviewArtifact; +import org.eclipse.osee.ats.core.review.IReviewArtifact; +import org.eclipse.osee.ats.core.review.defect.DefectItem; +import org.eclipse.osee.ats.core.review.defect.DefectItem.Severity; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.framework.core.data.IAttributeType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.jdk.core.util.AHTML; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Attribute; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public class UserRoleManager { + + private final WeakReference<AbstractReviewArtifact> artifactRef; + private boolean enabled = true; + private final static String ROLE_ITEM_TAG = "Role"; + private static final IAttributeType ATS_ROLE_STORAGE_TYPE = AtsAttributeTypes.Role; + + private final Matcher roleMatcher = java.util.regex.Pattern.compile( + "<" + ROLE_ITEM_TAG + ">(.*?)</" + ROLE_ITEM_TAG + ">", Pattern.DOTALL | Pattern.MULTILINE).matcher(""); + + public UserRoleManager(AbstractReviewArtifact artifact) { + this.artifactRef = new WeakReference<AbstractReviewArtifact>(artifact); + } + + public String getHtml() throws OseeCoreException { + if (getUserRoles().isEmpty()) { + return ""; + } + StringBuffer sb = new StringBuffer(); + sb.append(AHTML.addSpace(1) + AHTML.getLabelStr(AHTML.LABEL_FONT, "Defects")); + sb.append(getTable()); + return sb.toString(); + } + + public AbstractReviewArtifact getArtifact() throws OseeStateException { + if (artifactRef.get() == null) { + throw new OseeStateException("Artifact has been garbage collected"); + } + return artifactRef.get(); + } + + public Set<UserRole> getUserRoles() throws OseeCoreException { + Set<UserRole> roles = new HashSet<UserRole>(); + for (String xml : getArtifact().getAttributesToStringList(ATS_ROLE_STORAGE_TYPE)) { + roleMatcher.reset(xml); + while (roleMatcher.find()) { + UserRole item = new UserRole(roleMatcher.group()); + roles.add(item); + } + } + return roles; + } + + public Set<UserRole> getRoleUsersReviewComplete() throws OseeCoreException { + Set<UserRole> cRoles = new HashSet<UserRole>(); + for (UserRole role : getUserRoles(Role.Reviewer)) { + if (role.isCompleted()) { + cRoles.add(role); + } + } + return cRoles; + } + + public Set<User> getRoleUsersAuthorModerator() throws OseeCoreException { + Set<User> roles = getRoleUsers(Role.Author); + if (roles.isEmpty()) { + roles = getRoleUsers(Role.Moderator); + roles.add(UserManager.getUser()); + } + + return roles; + } + + public Set<UserRole> getUserRoles(Role role) throws OseeCoreException { + Set<UserRole> roles = new HashSet<UserRole>(); + for (UserRole uRole : getUserRoles()) { + if (uRole.getRole() == role) { + roles.add(uRole); + } + } + return roles; + } + + public Set<User> getRoleUsers(Role role) throws OseeCoreException { + Set<User> users = new HashSet<User>(); + for (UserRole uRole : getUserRoles()) { + if (uRole.getRole() == role) { + users.add(uRole.getUser()); + } + } + return users; + } + + private void saveRoleItems(Set<UserRole> defectItems, boolean persist, SkynetTransaction transaction) { + try { + // Change existing ones + for (Attribute<?> attr : getArtifact().getAttributes(ATS_ROLE_STORAGE_TYPE)) { + UserRole dbPromoteItem = new UserRole((String) attr.getValue()); + for (UserRole pItem : defectItems) { + if (pItem.equals(dbPromoteItem)) { + attr.setFromString(AXml.addTagData(ROLE_ITEM_TAG, pItem.toXml())); + } + } + } + Set<UserRole> dbPromoteItems = getUserRoles(); + // Remove deleted ones; items in dbPromoteItems that are not in promoteItems + for (UserRole delPromoteItem : org.eclipse.osee.framework.jdk.core.util.Collections.setComplement( + dbPromoteItems, defectItems)) { + for (Attribute<?> attr : getArtifact().getAttributes(ATS_ROLE_STORAGE_TYPE)) { + UserRole dbPromoteItem = new UserRole((String) attr.getValue()); + if (dbPromoteItem.equals(delPromoteItem)) { + attr.delete(); + } + } + } + // Add new ones: items in promoteItems that are not in dbPromoteItems + for (UserRole newPromoteItem : org.eclipse.osee.framework.jdk.core.util.Collections.setComplement(defectItems, + dbPromoteItems)) { + getArtifact().addAttributeFromString(ATS_ROLE_STORAGE_TYPE, + AXml.addTagData(ROLE_ITEM_TAG, newPromoteItem.toXml())); + } + updateAssignees(); + if (persist) { + getArtifact().persist(transaction); + } + rollupHoursSpentToReviewState(persist, transaction); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't create ats review role document", ex); + } + } + + public void addOrUpdateUserRole(UserRole userRole, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + Set<UserRole> roleItems = getUserRoles(); + boolean found = false; + for (UserRole uRole : roleItems) { + if (userRole.equals(uRole)) { + uRole.update(userRole); + found = true; + } + } + if (!found) { + roleItems.add(userRole); + } + saveRoleItems(roleItems, persist, transaction); + } + + private void updateAssignees() throws OseeCoreException { + // Set assignees based on roles that are not set as completed + Set<User> assignees = new HashSet<User>(); + for (UserRole uRole : getUserRoles()) { + if (!uRole.isCompleted() && uRole.getUser() != null) { + assignees.add(uRole.getUser()); + } + } + // If roles are all completed, then still need to select a user to assign to SMA + if (assignees.isEmpty()) { + if (getUserRoles(Role.Author).size() > 0) { + for (UserRole role : getUserRoles(Role.Author)) { + assignees.add(role.getUser()); + } + } else if (getUserRoles(Role.Moderator).size() > 0) { + for (UserRole role : getUserRoles(Role.Moderator)) { + assignees.add(role.getUser()); + } + } else { + assignees.add(UserManager.getUser()); + } + } + // Set assignees based on roles + getArtifact().getStateMgr().setAssignees(assignees); + } + + public void removeUserRole(UserRole userRole, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + Set<UserRole> roleItems = getUserRoles(); + roleItems.remove(userRole); + saveRoleItems(roleItems, persist, transaction); + } + + public String getTable() throws OseeCoreException { + StringBuilder builder = new StringBuilder(); + builder.append("<TABLE BORDER=\"1\" cellspacing=\"1\" cellpadding=\"3%\" width=\"100%\"><THEAD><TR><TH>Role</TH>" + "<TH>User</TH><TH>Hours</TH><TH>Major</TH><TH>Minor</TH><TH>Issues</TH>"); + for (UserRole item : getUserRoles()) { + User user = item.getUser(); + String name = ""; + if (user != null) { + name = user.getName(); + if (!Strings.isValid(name)) { + name = user.getName(); + } + } + builder.append("<TR>"); + builder.append("<TD>" + item.getRole().name() + "</TD>"); + builder.append("<TD>" + item.getUser().getName() + "</TD>"); + builder.append("<TD>" + item.getHoursSpentStr() + "</TD>"); + builder.append("<TD>" + getNumMajor(item.getUser()) + "</TD>"); + builder.append("<TD>" + getNumMinor(item.getUser()) + "</TD>"); + builder.append("<TD>" + getNumIssues(item.getUser()) + "</TD>"); + builder.append("</TR>"); + } + builder.append("</TABLE>"); + return builder.toString(); + } + + public int getNumMajor(User user) throws OseeCoreException { + int x = 0; + for (DefectItem dItem : ((IReviewArtifact) getArtifact()).getDefectManager().getDefectItems()) { + if (dItem.getSeverity() == Severity.Major && dItem.getUser() == user) { + x++; + } + } + return x; + } + + public int getNumMinor(User user) throws OseeCoreException { + int x = 0; + for (DefectItem dItem : ((IReviewArtifact) getArtifact()).getDefectManager().getDefectItems()) { + if (dItem.getSeverity() == Severity.Minor && dItem.getUser() == user) { + x++; + } + } + return x; + } + + public int getNumIssues(User user) throws OseeCoreException { + int x = 0; + for (DefectItem dItem : ((IReviewArtifact) getArtifact()).getDefectManager().getDefectItems()) { + if (dItem.getSeverity() == Severity.Issue && dItem.getUser() == user) { + x++; + } + } + return x; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void rollupHoursSpentToReviewState(boolean persist, SkynetTransaction transaction) throws OseeCoreException { + double hoursSpent = 0.0; + for (UserRole role : getUserRoles()) { + hoursSpent += role.getHoursSpent() == null ? 0 : role.getHoursSpent(); + } + AbstractWorkflowArtifact awa = getArtifact(); + awa.getStateMgr().setMetrics(hoursSpent, awa.getStateMgr().getPercentComplete(), true, UserManager.getUser(), + new Date()); + if (persist) { + getArtifact().persist(transaction); + } + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleValidator.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleValidator.java new file mode 100644 index 00000000000..8aa4a29e8ed --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/review/role/UserRoleValidator.java @@ -0,0 +1,62 @@ +/* + * Created on May 10, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.review.role; + +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.PeerToPeerReviewArtifact; +import org.eclipse.osee.ats.core.review.PeerToPeerReviewState; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class UserRoleValidator { + + public static UserRoleError isValid(Artifact artifact) { + try { + if (artifact.isOfType(AtsArtifactTypes.PeerToPeerReview)) { + if (artifact.getAttributeCount(AtsAttributeTypes.Role) == 0) { + return UserRoleError.OneRoleEntryRequired; + } + UserRoleError result = isUserRoleValid(artifact, UserRoleValidator.class.getSimpleName()); + if (!result.isOK()) { + return result; + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return UserRoleError.ExceptionValidatingRoles; + } + return UserRoleError.None; + } + + private static UserRoleError isUserRoleValid(Artifact artifact, String namespace) throws OseeCoreException { + if (artifact instanceof PeerToPeerReviewArtifact) { + PeerToPeerReviewArtifact peerToPeerReviewArtifact = (PeerToPeerReviewArtifact) artifact; + if (peerToPeerReviewArtifact.getUserRoleManager().getUserRoles(Role.Author).size() <= 0) { + return UserRoleError.MustHaveAtLeastOneAuthor; + } + if (peerToPeerReviewArtifact.getUserRoleManager().getUserRoles(Role.Reviewer).size() <= 0) { + return UserRoleError.MustHaveAtLeastOneReviewer; + } + // If in review state, all roles must have hours spent entered + if (peerToPeerReviewArtifact.isInState(PeerToPeerReviewState.Review) || peerToPeerReviewArtifact.isInState(PeerToPeerReviewState.Meeting)) { + for (UserRole uRole : peerToPeerReviewArtifact.getUserRoleManager().getUserRoles()) { + if (uRole.getHoursSpent() == null) { + return UserRoleError.HoursSpentMustBeEnteredForEachRole; + } + } + } + } + return UserRoleError.None; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/AbstractTaskableArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/AbstractTaskableArtifact.java new file mode 100644 index 00000000000..738c09b9880 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/AbstractTaskableArtifact.java @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.task; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsCacheManager; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.PercentCompleteTotalUtil; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactTypeManager; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public abstract class AbstractTaskableArtifact extends AbstractWorkflowArtifact { + + public AbstractTaskableArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + registerAtsWorldRelation(AtsRelationTypes.SmaToTask_Task); + } + + @Override + public void getSmaArtifactsOneLevel(AbstractWorkflowArtifact smaArtifact, Set<Artifact> artifacts) throws OseeCoreException { + super.getSmaArtifactsOneLevel(smaArtifact, artifacts); + artifacts.addAll(getTaskArtifacts()); + } + + @Override + public void atsDelete(Set<Artifact> deleteArts, Map<Artifact, Object> allRelated) throws OseeCoreException { + super.atsDelete(deleteArts, allRelated); + for (TaskArtifact taskArt : getTaskArtifacts()) { + taskArt.atsDelete(deleteArts, allRelated); + } + } + + @Override + public void transitioned(StateDefinition fromState, StateDefinition toState, Collection<User> toAssignees, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + super.transitioned(fromState, toState, toAssignees, persist, transaction); + for (TaskArtifact taskArt : getTaskArtifacts()) { + taskArt.parentWorkFlowTransitioned(fromState, toState, toAssignees, persist, transaction); + } + } + + public Collection<TaskArtifact> getTaskArtifacts() throws OseeCoreException { + return AtsCacheManager.getTaskArtifacts(this); + } + + public Collection<TaskArtifact> getTaskArtifactsSorted() throws OseeCoreException { + return AtsCacheManager.getTaskArtifacts(this); + } + + public Collection<TaskArtifact> getTaskArtifactsFromCurrentState() throws OseeCoreException { + return getTaskArtifacts(getStateMgr().getCurrentState()); + } + + public Collection<TaskArtifact> getTaskArtifacts(IWorkPage state) throws OseeCoreException { + List<TaskArtifact> arts = new ArrayList<TaskArtifact>(); + for (TaskArtifact taskArt : getTaskArtifacts()) { + if (taskArt.getSoleAttributeValue(AtsAttributeTypes.RelatedToState, "").equals(state.getPageName())) { + arts.add(taskArt); + } + } + return arts; + } + + public boolean hasTaskArtifacts() { + return getRelatedArtifactsCount(AtsRelationTypes.SmaToTask_Task) > 0; + } + + public TaskArtifact createNewTask(String title, Date createdDate, User createdBy) throws OseeCoreException { + return createNewTask(Arrays.asList(UserManager.getUser()), title, createdDate, createdBy); + } + + public TaskArtifact createNewTask(Collection<User> assignees, String title, Date createdDate, User createdBy) throws OseeCoreException { + TaskArtifact taskArt = null; + taskArt = + (TaskArtifact) ArtifactTypeManager.addArtifact(AtsArtifactTypes.Task, AtsUtilCore.getAtsBranch(), title); + + addRelation(AtsRelationTypes.SmaToTask_Task, taskArt); + taskArt.initializeNewStateMachine(assignees, new Date(), UserManager.getUser()); + + // Set parent state task is related to + taskArt.setSoleAttributeValue(AtsAttributeTypes.RelatedToState, getStateMgr().getCurrentStateName()); + + return taskArt; + } + + public Result areTasksComplete() { + try { + for (TaskArtifact taskArt : getTaskArtifacts()) { + if (taskArt.isInWork()) { + return new Result(false, "Task " + taskArt.getGuid() + " Not Complete"); + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return new Result(false, "Exception " + ex.getLocalizedMessage()); + } + return Result.TrueResult; + } + + public Result areTasksComplete(IWorkPage state) { + try { + for (TaskArtifact taskArt : getTaskArtifacts(state)) { + if (taskArt.isInWork()) { + return new Result(false, "Task " + taskArt.getGuid() + " Not Complete"); + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return new Result(false, "Exception " + ex.getLocalizedMessage()); + } + return Result.TrueResult; + } + + public int getNumTasksInWork() { + int num = 0; + try { + for (TaskArtifact taskArt : getTaskArtifacts()) { + if (taskArt.isInWork()) { + num++; + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return num; + } + + /** + * Return Estimated Task Hours of "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + * @return Returns the Estimated Hours + */ + @Override + public double getEstimatedHoursFromTasks(IWorkPage relatedToState) throws OseeCoreException { + double hours = 0; + for (TaskArtifact taskArt : getTaskArtifacts(relatedToState)) { + hours += taskArt.getEstimatedHoursTotal(); + } + return hours; + } + + /** + * Return Estimated Hours for all tasks + */ + @Override + public double getEstimatedHoursFromTasks() throws OseeCoreException { + double hours = 0; + for (TaskArtifact taskArt : getTaskArtifacts()) { + hours += taskArt.getEstimatedHoursFromArtifact(); + } + return hours; + + } + + /** + * Return Remain Task Hours of "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + * @return Returns the Remain Hours + */ + public double getRemainHoursFromTasks(IWorkPage relatedToState) throws OseeCoreException { + double hours = 0; + for (TaskArtifact taskArt : getTaskArtifacts(relatedToState)) { + hours += taskArt.getRemainHoursFromArtifact(); + } + return hours; + } + + /** + * Return Remain Hours for all tasks + */ + public double getRemainHoursFromTasks() throws OseeCoreException { + double hours = 0; + for (TaskArtifact taskArt : getTaskArtifacts()) { + hours += taskArt.getRemainHoursFromArtifact(); + } + return hours; + + } + + /** + * Return Total Percent Complete / # Tasks for "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + * @return Returns the Percent Complete. + */ + public int getPercentCompleteFromTasks(IWorkPage relatedToState) throws OseeCoreException { + int spent = 0; + Collection<TaskArtifact> taskArts = getTaskArtifacts(relatedToState); + for (TaskArtifact taskArt : taskArts) { + spent += PercentCompleteTotalUtil.getPercentCompleteTotal(taskArt); + } + if (spent == 0) { + return 0; + } + return spent / taskArts.size(); + } + + public Collection<TaskArtifact> createTasks(List<String> titles, List<User> assignees, Date createdDate, User createdBy, SkynetTransaction transaction) throws OseeCoreException { + List<TaskArtifact> tasks = new ArrayList<TaskArtifact>(); + for (String title : titles) { + TaskArtifact taskArt = createNewTask(title, createdDate, createdBy); + if (assignees != null && !assignees.isEmpty()) { + Set<User> users = new HashSet<User>(); // NOPMD by b0727536 on 9/29/10 8:51 AM + for (User art : assignees) { + users.add(art); + } + taskArt.getStateMgr().setAssignees(users); + } + tasks.add(taskArt); + taskArt.persist(transaction); + } + return tasks; + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskArtifact.java new file mode 100644 index 00000000000..4c635fa358f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskArtifact.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.task; + +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.EstimatedHoursUtil; +import org.eclipse.osee.ats.core.workflow.PercentCompleteTotalUtil; +import org.eclipse.osee.ats.core.workflow.StateManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionOption; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.IATSStateMachineArtifact; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public class TaskArtifact extends AbstractWorkflowArtifact implements IATSStateMachineArtifact { + + public TaskArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + public boolean isRelatedToParentWorkflowCurrentState() throws OseeCoreException { + return getSoleAttributeValueAsString(AtsAttributeTypes.RelatedToState, "").equals( + getParentAWA().getStateMgr().getCurrentStateName()); + } + + public boolean isUsingTaskResolutionOptions() throws OseeCoreException { + return getTaskResolutionOptionDefintions().size() > 0; + } + + public List<TaskResOptionDefinition> getTaskResolutionOptionDefintions() throws OseeCoreException { + TeamWorkFlowArtifact team = getParentTeamWorkflow(); + if (team == null) { + return TaskResolutionOptionRule.EMPTY_TASK_RESOLUTION_OPTIONS; + } + return TaskResolutionOptionRule.getTaskResolutionOptions(team.getStateDefinition()); + } + + public TaskResOptionDefinition getTaskResolutionOptionDefinition(String optionName) throws OseeCoreException { + for (TaskResOptionDefinition def : getTaskResolutionOptionDefintions()) { + if (def.getName().equals(optionName)) { + return def; + } + } + return null; + } + + public List<TaskResOptionDefinition> getTaskResolutionOptionDefintions(String stateName) throws OseeCoreException { + TeamWorkFlowArtifact team = getParentTeamWorkflow(); + if (team == null) { + return TaskResolutionOptionRule.EMPTY_TASK_RESOLUTION_OPTIONS; + } + return TaskResolutionOptionRule.getTaskResolutionOptions(team.getStateDefinitionByName(stateName)); + } + + public TaskResOptionDefinition getTaskResolutionOptionDefinition(String stateName, String optionName) throws OseeCoreException { + for (TaskResOptionDefinition def : getTaskResolutionOptionDefintions(stateName)) { + if (def.getName().equals(optionName)) { + return def; + } + } + return null; + } + + @Override + public String getDescription() { + try { + return getSoleAttributeValue(AtsAttributeTypes.Description, ""); + } catch (Exception ex) { + return "Error: " + ex.getLocalizedMessage(); + } + } + + public Result transitionToCompleted(double additionalHours, SkynetTransaction transaction, TransitionOption... transitionOption) { + if (isInState(TeamState.Completed)) { + return Result.TrueResult; + } + // Assign current user if unassigned + try { + if (getStateMgr().isUnAssigned()) { + getStateMgr().setAssignee(UserManager.getUser()); + } + getStateMgr().updateMetrics(additionalHours, 100, true); + setSoleAttributeValue(AtsAttributeTypes.PercentComplete, 100); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + TransitionManager transitionMgr = new TransitionManager(this); + Result result = transitionMgr.transition(TaskStates.Completed, (User) null, transaction, transitionOption); + return result; + } + + public Result transitionToInWork(User toUser, int percentComplete, double additionalHours, SkynetTransaction transaction, TransitionOption... transitionOption) throws OseeCoreException { + if (isInState(TaskStates.InWork)) { + return Result.TrueResult; + } + TransitionManager transitionMgr = new TransitionManager(this); + Result result = transitionMgr.transition(TaskStates.InWork, toUser, transaction, transitionOption); + if (getStateMgr().getPercentComplete() != percentComplete || additionalHours > 0) { + getStateMgr().updateMetrics(additionalHours, percentComplete, true); + setSoleAttributeValue(AtsAttributeTypes.PercentComplete, percentComplete); + } + if (Collections.getAggregate(transitionOption).contains(TransitionOption.Persist)) { + saveSMA(transaction); + } + return result; + } + + /** + * Tasks must transition in/out of completed when percent changes between 100 and <100. This method will handle these + * cases. + */ + public Result statusPercentChanged(double additionalHours, int percentComplete, SkynetTransaction transaction) throws OseeCoreException { + if (percentComplete == 100 && !isCompleted()) { + Result result = transitionToCompleted(additionalHours, transaction, TransitionOption.None); + return result; + } else if (percentComplete != 100 && isCompleted()) { + Result result = + transitionToInWork(UserManager.getUser(), percentComplete, additionalHours, transaction, + TransitionOption.Persist); + return result; + } + // Case where already completed and statusing, just add additional hours to InWork state + else if (percentComplete == 100 && isCompleted()) { + if (additionalHours > 0) { + getStateMgr().updateMetrics(TaskStates.InWork, additionalHours, percentComplete, true); + setSoleAttributeValue(AtsAttributeTypes.PercentComplete, percentComplete); + } + } else { + getStateMgr().updateMetrics(additionalHours, percentComplete, true); + setSoleAttributeValue(AtsAttributeTypes.PercentComplete, percentComplete); + } + return Result.TrueResult; + } + + public Result parentWorkFlowTransitioned(StateDefinition fromState, StateDefinition toState, Collection<User> toAssignees, boolean persist, SkynetTransaction transaction, TransitionOption... transitionOption) throws OseeCoreException { + if (toState.getPageName().equals(TeamState.Cancelled.getPageName()) && isInWork()) { + TransitionManager transitionMgr = new TransitionManager(this); + Result result = transitionMgr.transitionToCancelled("Parent Cancelled", transaction, transitionOption); + return result; + } else if (fromState.getPageName().equals(TeamState.Cancelled.getPageName()) && isCancelled()) { + Result result = transitionToInWork(UserManager.getUser(), 99, 0, transaction, transitionOption); + return result; + } + return Result.TrueResult; + } + + @Override + public double getManHrsPerDayPreference() throws OseeCoreException { + return getParentAWA().getManHrsPerDayPreference(); + } + + @Override + public AbstractWorkflowArtifact getParentAWA() throws OseeCoreException { + if (parentAwa != null) { + return parentAwa; + } + Collection<AbstractWorkflowArtifact> awas = + getRelatedArtifacts(AtsRelationTypes.SmaToTask_Sma, AbstractWorkflowArtifact.class); + if (awas.isEmpty()) { + throw new OseeStateException("Task has no parent [%s]", getHumanReadableId()); + } + parentAwa = awas.iterator().next(); + return parentAwa; + } + + @Override + public Artifact getParentActionArtifact() throws OseeCoreException { + if (parentAction != null) { + return parentAction; + } + parentAction = getParentTeamWorkflow().getParentActionArtifact(); + return parentAction; + } + + @Override + public TeamWorkFlowArtifact getParentTeamWorkflow() throws OseeCoreException { + if (parentTeamArt != null) { + return parentTeamArt; + } + AbstractWorkflowArtifact awa = getParentAWA(); + if (awa.isTeamWorkflow()) { + parentTeamArt = (TeamWorkFlowArtifact) awa; + } + return parentTeamArt; + } + + @Override + public Collection<User> getImplementers() throws OseeCoreException { + return StateManager.getImplementersByState(this, TaskStates.InWork); + } + + @Override + public double getWorldViewWeeklyBenefit() { + return 0; + } + + @Override + public String getWorldViewSWEnhancement() throws OseeCoreException { + AbstractWorkflowArtifact awa = getParentAWA(); + if (awa != null) { + return awa.getWorldViewSWEnhancement(); + } + return ""; + } + + @Override + public double getRemainHoursFromArtifact() throws OseeCoreException { + if (isCompleted() || isCancelled()) { + return 0; + } + double est = EstimatedHoursUtil.getEstimatedHours(this); + if (PercentCompleteTotalUtil.getPercentCompleteTotal(this) == 0) { + return est; + } + double percent = getStateMgr().getPercentComplete(TaskStates.InWork); + if (percent == 0) { + return est; + } + return est - ((est * percent) / 100.0); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResOptionDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResOptionDefinition.java new file mode 100644 index 00000000000..921922d3f3f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResOptionDefinition.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.task; + +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * @author Donald G. Dunne + */ +public class TaskResOptionDefinition { + + private String name; + private String desc; + private boolean completeable; + private String color; + private String percent; + public final static String ATS_TASK_OPTION_TAG = "AtsTaskOption"; + + public TaskResOptionDefinition() { + name = ""; + desc = ""; + percent = ""; + completeable = false; + } + + /** + * @param completeable true/false of whether option allows task to be transitioned to complete + */ + public TaskResOptionDefinition(String name, String desc, String completeable, String color, String defaultPercent) { + this(name, desc, completeable.equals("true"), color, defaultPercent); + } + + public TaskResOptionDefinition(String name, String desc, boolean completeable, String defaultPercent) { + this(name, desc, completeable, "", defaultPercent); + } + + public void setFromElement(Element element) throws OseeCoreException { + for (int x = 0; x < element.getAttributes().getLength(); x++) { + Node node = element.getAttributes().item(x); + String nodeName = node.getNodeName(); + if (nodeName.equals(Field.name.name())) { + name = node.getNodeValue(); + } else if (nodeName.equals(Field.desc.name())) { + desc = node.getNodeValue(); + } else if (nodeName.equals(Field.complete.name())) { + completeable = Boolean.parseBoolean(node.getNodeValue()); + } else if (nodeName.equals(Field.color.name())) { + color = node.getNodeValue(); + } else if (nodeName.equals(Field.percent.name())) { + percent = node.getNodeValue(); + } else { + throw new OseeArgumentException("Unknow Task Resolution Option Attribute [%s]", nodeName); + } + } + } + + /** + * @param completeable true if option allows task to be transitioned to complete + * @param color BLUE, RED, etc...; "" for black + */ + public TaskResOptionDefinition(String name, String desc, boolean completeable, String color, String defaultPercent) { + this.name = name; + this.desc = desc; + this.completeable = completeable; + this.color = color; + this.percent = defaultPercent; + } + + /** + * @return true if resolution option allows task to be transitioned to complete + */ + public boolean isCompleteable() { + return completeable; + } + + public String getDesc() { + return desc; + } + + public String getName() { + return name; + } + + private enum Field { + name, + desc, + complete, + percent, + color + }; + + public void setFromXml(String xml) throws OseeCoreException { + for (Field field : Field.values()) { + String data = AXml.getTagData(xml, field.name()); + if (field == Field.name) { + setName(data); + } else if (field == Field.color) { + setColor(data); + } else if (field == Field.desc) { + setDesc(data); + } else if (field == Field.percent) { + setPercent(data); + } else if (field == Field.complete) { + setComplete(data.equals("true")); + } else { + throw new OseeArgumentException("Unexpected field"); + } + } + } + + public String toXml() throws OseeCoreException { + StringBuffer sb = new StringBuffer("<" + ATS_TASK_OPTION_TAG + ">"); + for (Field field : Field.values()) { + String str = ""; + if (field == Field.name) { + str = getName(); + } else if (field == Field.color) { + str = getColor(); + } else if (field == Field.desc) { + str = getDesc(); + } else if (field == Field.percent) { + str = getPercent(); + } else if (field == Field.complete) { + str = isCompleteable() ? "true" : "false"; + } else { + throw new OseeCoreException("Unexpected field"); + } + sb.append(AXml.addTagData(field.name(), str)); + } + sb.append("</" + ATS_TASK_OPTION_TAG + ">"); + return sb.toString(); + } + + public void setComplete(boolean complete) { + this.completeable = complete; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public void setName(String name) { + this.name = name; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + + public String getPercent() { + return percent; + } + + public void setPercent(String defaultPercent) { + this.percent = defaultPercent; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResolutionOptionRule.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResolutionOptionRule.java new file mode 100644 index 00000000000..e8eaac6eddb --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskResolutionOptionRule.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.task; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.workdef.RuleDefinition; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.framework.core.enums.CoreArtifactTypes; +import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; +import org.eclipse.osee.framework.core.exception.ArtifactDoesNotExist; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeExceptions; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.jdk.core.util.xml.Jaxp; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * @author Donald G. Dunne + */ +public class TaskResolutionOptionRule { + + private final List<TaskResOptionDefinition> options = new ArrayList<TaskResOptionDefinition>(); + public final static String ATS_TASK_OPTIONS_TAG = "AtsTaskOptions"; + public final static String WORK_TYPE = "AtsTaskResolutionOptions"; + public final static List<TaskResOptionDefinition> EMPTY_TASK_RESOLUTION_OPTIONS = + new ArrayList<TaskResOptionDefinition>(); + + public static List<TaskResOptionDefinition> getTaskResolutionOptions(StateDefinition stateDefinition) throws OseeCoreException { + TaskResolutionOptionRule taskResolutionOptionRule = getTaskResolutionOptionRule(stateDefinition); + if (taskResolutionOptionRule != null) { + return taskResolutionOptionRule.getOptions(); + } + return EMPTY_TASK_RESOLUTION_OPTIONS; + } + + public static TaskResolutionOptionRule getTaskResolutionOptionRule(StateDefinition stateDefinition) throws OseeCoreException { + List<RuleDefinition> wids = new ArrayList<RuleDefinition>(); + for (RuleDefinition ruleDef : stateDefinition.getRules()) { + if (ruleDef.getName().contains("taskResolutionOptions")) { + wids.add(ruleDef); + } + } + if (wids.isEmpty()) { + return null; + } + RuleDefinition ruleDefinition = wids.iterator().next(); + if (ruleDefinition != null) { + TaskResolutionOptionRule taskResolutionOptionRule = new TaskResolutionOptionRule(); + taskResolutionOptionRule.fromXml(getTaskResolutionRuleXml(ruleDefinition)); + return taskResolutionOptionRule; + } + return null; + } + + public static String getTaskResolutionRuleXml(RuleDefinition ruleDefinition) throws OseeCoreException { + // If this rule was converted from WorkRuleDefinition, it will have task options + String xml = ruleDefinition.getWorkDataValue(ATS_TASK_OPTIONS_TAG); + if (Strings.isValid(xml)) { + return xml; + } + // Else, look for a GeneralData artifact of same name as rule to retrieve options xml string + Artifact artifact = null; + try { + artifact = + ArtifactQuery.getArtifactFromTypeAndName(CoreArtifactTypes.GeneralData, ruleDefinition.getName(), + AtsUtilCore.getAtsBranch()); + return artifact.getSoleAttributeValue(CoreAttributeTypes.GeneralStringData, ""); + } catch (ArtifactDoesNotExist ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex, "GeneralData artifact named [%s] does not exist", + ruleDefinition.getName()); + } + return ""; + } + + public void setFromDoc(Document doc) throws OseeCoreException { + NodeList nodes = doc.getElementsByTagName(TaskResOptionDefinition.ATS_TASK_OPTION_TAG); + if (nodes.getLength() > 0) { + for (int x = 0; x < nodes.getLength(); x++) { + Element element = (Element) nodes.item(x); + TaskResOptionDefinition trd = new TaskResOptionDefinition(); + trd.setFromElement(element); + options.add(trd); + } + } + } + + public void fromXml(String xmlStr) throws OseeCoreException { + try { + setFromDoc(Jaxp.readXmlDocument(xmlStr)); + } catch (Exception ex) { + OseeExceptions.wrapAndThrow(ex); + } + } + + public String toXml() throws OseeCoreException { + StringBuffer sb = new StringBuffer(); + sb.append("<" + TaskResOptionDefinition.ATS_TASK_OPTION_TAG + ">\n"); + for (TaskResOptionDefinition def : options) { + sb.append(def.toXml()); + sb.append("\n"); + } + sb.append("</"); + sb.append(TaskResOptionDefinition.ATS_TASK_OPTION_TAG); + sb.append(">\n"); + return sb.toString(); + } + + public List<TaskResOptionDefinition> getOptions() { + return options; + } + + /** + * Return the order index number of the given option name. Used for comparisons of resolutions like < and > by + * getting both indexes and doing a mathmatical comparison. + * + * @return index number (starting at 1) or null if not found + */ + public Integer getResolutionOptionOrderIndex(String name) { + int x = 1; + for (TaskResOptionDefinition option : options) { + if (option.getName().equals(name)) { + return x; + } + x++; + } + return null; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskStates.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskStates.java new file mode 100644 index 00000000000..12f12389bdf --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/task/TaskStates.java @@ -0,0 +1,24 @@ +package org.eclipse.osee.ats.core.task; + +import java.util.List; +import org.eclipse.osee.framework.core.util.WorkPageAdapter; +import org.eclipse.osee.framework.core.util.WorkPageType; + +public class TaskStates extends WorkPageAdapter { + public static TaskStates InWork = new TaskStates("InWork", WorkPageType.Working); + public static TaskStates Completed = new TaskStates("Completed", WorkPageType.Completed); + public static TaskStates Cancelled = new TaskStates("Cancelled", WorkPageType.Cancelled); + + private TaskStates(String pageName, WorkPageType workPageType) { + super(TaskStates.class, pageName, workPageType); + } + + public static TaskStates valueOf(String pageName) { + return WorkPageAdapter.valueOfPage(TaskStates.class, pageName); + } + + public List<TaskStates> values() { + return WorkPageAdapter.pages(TaskStates.class); + } + +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/SimpleTeamState.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/SimpleTeamState.java new file mode 100644 index 00000000000..442ccb5df98 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/SimpleTeamState.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.team; + +import org.eclipse.osee.framework.core.util.WorkPageAdapter; +import org.eclipse.osee.framework.core.util.WorkPageType; + +public class SimpleTeamState extends WorkPageAdapter { + private final String name; + + public SimpleTeamState(String name, WorkPageType workPageType) { + super(SimpleTeamState.class, name, workPageType); + this.name = name; + } + + @Override + public String getPageName() { + return name; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamState.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamState.java new file mode 100644 index 00000000000..8d27fe68b57 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamState.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.team; + +import java.util.List; +import org.eclipse.osee.framework.core.util.WorkPageAdapter; +import org.eclipse.osee.framework.core.util.WorkPageType; + +public class TeamState extends WorkPageAdapter { + public static TeamState Endorse = new TeamState("Endorse", WorkPageType.Working); + public static TeamState Analyze = new TeamState("Analyze", WorkPageType.Working); + public static TeamState Authorize = new TeamState("Authorize", WorkPageType.Working); + public static TeamState Implement = new TeamState("Implement", WorkPageType.Working); + public static TeamState Completed = new TeamState("Completed", WorkPageType.Completed); + public static TeamState Cancelled = new TeamState("Cancelled", WorkPageType.Cancelled); + + private TeamState(String pageName, WorkPageType workPageType) { + super(TeamState.class, pageName, workPageType); + } + + public static TeamState valueOf(String pageName) { + return WorkPageAdapter.valueOfPage(TeamState.class, pageName); + } + + public static List<TeamState> values() { + return WorkPageAdapter.pages(TeamState.class); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowArtifact.java new file mode 100644 index 00000000000..efac1fe38a9 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowArtifact.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.team; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.branch.AtsBranchManagerCore; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.AbstractReviewArtifact; +import org.eclipse.osee.ats.core.review.ReviewManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.util.AtsCacheManager; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.ActionArtifact; +import org.eclipse.osee.ats.core.workflow.ActionArtifactRollup; +import org.eclipse.osee.ats.core.workflow.ActionableItemManagerCore; +import org.eclipse.osee.ats.core.workflow.StateManager; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.IATSStateMachineArtifact; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public class TeamWorkFlowArtifact extends AbstractTaskableArtifact implements IATSStateMachineArtifact { + + private ActionableItemManagerCore actionableItemsDam; + + public TeamWorkFlowArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + registerAtsWorldRelation(AtsRelationTypes.TeamWorkflowToReview_Review); + } + + @Override + public void getSmaArtifactsOneLevel(AbstractWorkflowArtifact smaArtifact, Set<Artifact> artifacts) throws OseeCoreException { + super.getSmaArtifactsOneLevel(smaArtifact, artifacts); + try { + if (getTargetedVersion() != null) { + artifacts.add(getTargetedVersion()); + } + artifacts.addAll(ReviewManager.getReviews(this)); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + @Override + public String getArtifactSuperTypeName() { + return "Team Workflow"; + } + + @Override + public void saveSMA(SkynetTransaction transaction) { + super.saveSMA(transaction); + try { + ActionArtifactRollup rollup = new ActionArtifactRollup(getParentActionArtifact(), transaction); + rollup.resetAttributesOffChildren(); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't reset Action parent of children", ex); + } + } + + @Override + public String getDescription() { + try { + return getSoleAttributeValue(AtsAttributeTypes.Description, ""); + } catch (Exception ex) { + return "Error: " + ex.getLocalizedMessage(); + } + } + + @Override + public boolean isValidationRequired() throws OseeCoreException { + return getSoleAttributeValue(AtsAttributeTypes.ValidationRequired, false); + } + + @Override + public String getEditorTitle() throws OseeCoreException { + try { + if (getTargetedVersion() != null) { + return getType() + ": " + "[" + getTargetedVersionStr() + "] - " + getName(); + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return super.getEditorTitle(); + } + + @Override + public void onInitializationComplete() throws OseeCoreException { + super.onInitializationComplete(); + initializeSMA(); + } + + @Override + protected void initializeSMA() throws OseeCoreException { + super.initializeSMA(); + actionableItemsDam = new ActionableItemManagerCore(this); + } + + public ActionableItemManagerCore getActionableItemsDam() { + return actionableItemsDam; + } + + public void setTeamDefinition(TeamDefinitionArtifact tda) throws OseeCoreException { + this.setSoleAttributeValue(AtsAttributeTypes.TeamDefinition, tda.getGuid()); + } + + public TeamDefinitionArtifact getTeamDefinition() throws OseeCoreException, OseeCoreException { + String guid = this.getSoleAttributeValue(AtsAttributeTypes.TeamDefinition, ""); + if (!Strings.isValid(guid)) { + throw new OseeArgumentException("TeamWorkflow [%s] has no TeamDefinition associated.", getHumanReadableId()); + } + return AtsCacheManager.getTeamDefinitionArtifact(guid); + } + + public String getTeamName() { + try { + return getTeamDefinition().getName(); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return "!Error"; + } + } + + @Override + public String getType() { + return getTeamName() + " Workflow"; + } + + @Override + public void atsDelete(Set<Artifact> deleteArts, Map<Artifact, Object> allRelated) throws OseeCoreException { + super.atsDelete(deleteArts, allRelated); + for (AbstractReviewArtifact reviewArt : ReviewManager.getReviews(this)) { + reviewArt.atsDelete(deleteArts, allRelated); + } + } + + @Override + public TeamWorkFlowArtifact getParentTeamWorkflow() { + parentTeamArt = this; + return parentTeamArt; + } + + @Override + public Artifact getParentAtsArtifact() throws OseeCoreException { + return getParentActionArtifact(); + } + + @Override + public ActionArtifact getParentActionArtifact() throws OseeCoreException { + if (parentAction != null) { + return parentAction; + } + Collection<Artifact> arts = getRelatedArtifacts(AtsRelationTypes.ActionToWorkflow_Action); + if (arts.isEmpty()) { + throw new OseeStateException("Team [%s] has no parent Action", getGuid()); + } else if (arts.size() > 1) { + throw new OseeStateException("Team [%s] has multiple parent Actions", getGuid()); + } + parentAction = (ActionArtifact) arts.iterator().next(); + return parentAction; + } + + @Override + public AbstractWorkflowArtifact getParentAWA() { + return null; + } + + @Override + public double getManHrsPerDayPreference() throws OseeCoreException { + try { + return getTeamDefinition().getManDayHrsFromItemAndChildren(); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return super.getManHrsPerDayPreference(); + } + + @Override + public Collection<User> getImplementers() throws OseeCoreException { + return StateManager.getImplementersByState(this, TeamState.Implement); + } + + @Override + public double getWorldViewWeeklyBenefit() throws OseeCoreException { + if (isAttributeTypeValid(AtsAttributeTypes.WeeklyBenefit)) { + return 0; + } + String value = getSoleAttributeValue(AtsAttributeTypes.WeeklyBenefit, ""); + if (!Strings.isValid(value)) { + return 0; + } + return new Float(value).doubleValue(); + } + + public Branch getWorkingBranch() throws OseeCoreException { + return AtsBranchManagerCore.getWorkingBranch(this); + } + + public String getBranchName() { + String smaTitle = getName(); + if (smaTitle.length() > 40) { + smaTitle = smaTitle.substring(0, 39) + "..."; + } + String typeName = TeamWorkFlowManager.getArtifactTypeShortName(this); + if (Strings.isValid(typeName)) { + return String.format("%s - %s - %s", getHumanReadableId(), typeName, smaTitle); + } else { + return String.format("%s - %s", getHumanReadableId(), smaTitle); + } + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowManager.java new file mode 100644 index 00000000000..bdd48c0314b --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkFlowManager.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.team; + +import java.util.Date; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.ITeamWorkflowProvider; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.ats.core.workflow.transition.TransitionOption; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * Methods in support of programatically transitioning the DefaultWorkFlow through it's states. Only to be used for the + * DefaultTeamWorkflow of Endorse->Analyze->Auth->Implement->Complete + * + * @author Donald G. Dunne + */ +public class TeamWorkFlowManager { + + private final TeamWorkFlowArtifact teamArt; + + public TeamWorkFlowManager(TeamWorkFlowArtifact teamArt) { + this.teamArt = teamArt; + } + + /** + * Quickly transition to a state with minimal metrics and data entered. Should only be used for automated transition + * for things such as developmental testing and demos. + * + * @param user User to transition to OR null if should use user of current state + */ + public Result transitionTo(TeamState toState, User user, boolean popup, SkynetTransaction transaction) throws OseeCoreException { + Date date = new Date(); + if (teamArt.isInState(TeamState.Endorse)) { + Result result = processEndorseState(popup, teamArt, user, date, transaction); + if (result.isFalse()) { + return result; + } + } + if (toState == TeamState.Analyze) { + return Result.TrueResult; + } + + Result result = processAnalyzeState(popup, teamArt, user, date, transaction); + if (result.isFalse()) { + return result; + } + + if (toState == TeamState.Authorize) { + return Result.TrueResult; + } + + result = processAuthorizeState(popup, teamArt, user, date, transaction); + if (result.isFalse()) { + return result; + } + + if (toState == TeamState.Implement) { + return Result.TrueResult; + } + + result = transitionToState(popup, teamArt, TeamState.Completed, user, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + + } + + private User getUserOrDefault(User user) throws OseeCoreException { + if (user == null) { + return UserManager.getUser(); + } + return user; + } + + private Result processAuthorizeState(boolean popup, TeamWorkFlowArtifact teamArt, User user, Date date, SkynetTransaction transaction) throws OseeCoreException { + Result result = setAuthorizeData(popup, 100, .2, getUserOrDefault(user), date); + if (result.isFalse()) { + return result; + } + result = transitionToState(popup, teamArt, TeamState.Implement, user, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + } + + private Result processAnalyzeState(boolean popup, TeamWorkFlowArtifact teamArt, User user, Date date, SkynetTransaction transaction) throws OseeCoreException { + Result result = setAnalyzeData(popup, null, null, 1, 100, .2, getUserOrDefault(user), date); + if (result.isFalse()) { + return result; + } + result = transitionToState(popup, teamArt, TeamState.Authorize, user, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + } + + private Result processEndorseState(boolean popup, TeamWorkFlowArtifact teamArt, User user, Date date, SkynetTransaction transaction) throws OseeCoreException { + Result result = setEndorseData(popup, null, 100, .2, getUserOrDefault(user), date); + if (result.isFalse()) { + return result; + } + result = transitionToState(popup, teamArt, TeamState.Analyze, user, transaction); + if (result.isFalse()) { + return result; + } + return Result.TrueResult; + } + + private Result transitionToState(boolean popup, TeamWorkFlowArtifact teamArt, IWorkPage toState, User user, SkynetTransaction transaction) throws OseeCoreException { + TransitionManager transitionMgr = new TransitionManager(teamArt); + Result result = + transitionMgr.transition(toState, + (user == null ? teamArt.getStateMgr().getAssignees().iterator().next() : user), transaction, + TransitionOption.None); + return result; + } + + public Result setEndorseData(boolean popup, String propRes, int statePercentComplete, double stateHoursSpent, User user, Date date) throws OseeCoreException { + if (!teamArt.isInState(TeamState.Endorse)) { + Result result = new Result("Action not in Endorse state"); + if (result.isFalse() && popup) { + return result; + } + } + teamArt.getStateMgr().setMetrics(TeamState.Endorse, stateHoursSpent, statePercentComplete, true, user, date); + return Result.TrueResult; + } + + public Result setAnalyzeData(boolean popup, String problem, String propRes, double hourEstimate, int statePercentComplete, double stateHoursSpent, User user, Date date) throws OseeCoreException { + if (!teamArt.isInState(TeamState.Analyze)) { + Result result = new Result("Action not in Analyze state"); + if (result.isFalse() && popup) { + return result; + } + } + teamArt.setSoleAttributeValue(AtsAttributeTypes.EstimatedHours, hourEstimate); + teamArt.getStateMgr().setMetrics(TeamState.Analyze, stateHoursSpent, statePercentComplete, true, user, date); + return Result.TrueResult; + } + + public Result setAuthorizeData(boolean popup, int statePercentComplete, double stateHoursSpent, User user, Date date) throws OseeCoreException { + if (!teamArt.isInState(TeamState.Authorize)) { + Result result = new Result("Action not in Authorize state"); + if (result.isFalse() && popup) { + return result; + } + } + teamArt.getStateMgr().setMetrics(TeamState.Authorize, stateHoursSpent, statePercentComplete, true, user, date); + return Result.TrueResult; + } + + public Result setImplementData(boolean popup, String resolution, int statePercentComplete, double stateHoursSpent, User user, Date date) throws OseeCoreException { + if (!teamArt.isInState(TeamState.Implement)) { + Result result = new Result("Action not in Implement state"); + if (result.isFalse() && popup) { + return result; + } + } + teamArt.getStateMgr().setMetrics(TeamState.Implement, stateHoursSpent, statePercentComplete, true, user, date); + return Result.TrueResult; + } + + /** + * Assigned or computed Id that will show at the top of the editor + */ + public static String getPcrId(AbstractWorkflowArtifact awa) throws OseeCoreException { + TeamWorkFlowArtifact teamArt = awa.getParentTeamWorkflow(); + if (teamArt != null) { + for (ITeamWorkflowProvider atsTeamWorkflow : TeamWorkflowProviders.getAtsTeamWorkflowExtensions()) { + String pcrId = atsTeamWorkflow.getPcrId(teamArt); + if (Strings.isValid(pcrId)) { + return pcrId; + } + } + return teamArt.getTeamName() + " " + awa.getHumanReadableId(); + } + return ""; + } + + public static String getArtifactTypeShortName(TeamWorkFlowArtifact teamArt) { + for (ITeamWorkflowProvider atsTeamWorkflow : TeamWorkflowProviders.getAtsTeamWorkflowExtensions()) { + String typeName = atsTeamWorkflow.getArtifactTypeShortName(teamArt); + if (Strings.isValid(typeName)) { + return typeName; + } + } + return null; + } + + public static TeamWorkFlowArtifact cast(Artifact artifact) { + if (artifact instanceof AbstractWorkflowArtifact) { + return (TeamWorkFlowArtifact) artifact; + } + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkflowProviders.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkflowProviders.java new file mode 100644 index 00000000000..98a992755c5 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/team/TeamWorkflowProviders.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.team; + +import java.util.HashSet; +import java.util.Set; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.workflow.ITeamWorkflowProvider; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.osgi.framework.Bundle; + +/** + * @author Donald G. Dunne + */ +public final class TeamWorkflowProviders { + + private static Set<ITeamWorkflowProvider> teamWorkflowProvider; + + private TeamWorkflowProviders() { + // private constructor + } + + public static Set<IArtifactType> getAllTeamWorkflowArtifactTypes() throws OseeCoreException { + Set<IArtifactType> artifactTypes = new HashSet<IArtifactType>(); + artifactTypes.add(AtsArtifactTypes.TeamWorkflow); + for (ITeamWorkflowProvider ext : getAtsTeamWorkflowExtensions()) { + artifactTypes.addAll(ext.getTeamWorkflowArtifactTypes()); + } + return artifactTypes; + } + + /* + * due to lazy initialization, this function is non-reentrant therefore, the synchronized keyword is necessary + */ + public synchronized static Set<ITeamWorkflowProvider> getAtsTeamWorkflowExtensions() { + if (teamWorkflowProvider != null) { + return teamWorkflowProvider; + } + teamWorkflowProvider = new HashSet<ITeamWorkflowProvider>(); + + IExtensionPoint point = + Platform.getExtensionRegistry().getExtensionPoint("org.eclipse.osee.ats.core.AtsTeamWorkflowProvider"); + if (point == null) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't access AtsTeamWorkflowProvider extension point"); + return teamWorkflowProvider; + } + IExtension[] extensions = point.getExtensions(); + for (IExtension extension : extensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + String classname = null; + String bundleName = null; + for (IConfigurationElement el : elements) { + if (el.getName().equals("AtsTeamWorkflowProvider")) { + classname = el.getAttribute("classname"); + bundleName = el.getContributor().getName(); + if (classname != null && bundleName != null) { + Bundle bundle = Platform.getBundle(bundleName); + try { + Class<?> taskClass = bundle.loadClass(classname); + Object obj = taskClass.newInstance(); + teamWorkflowProvider.add((ITeamWorkflowProvider) obj); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, + "Error loading AtsTeamWorkflowProvider extension", ex); + } + } + } + } + } + return teamWorkflowProvider; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/ATSAttributes.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/ATSAttributes.java new file mode 100644 index 00000000000..c292f2666ed --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/ATSAttributes.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.type; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Donald G. Dunne + */ +public class ATSAttributes { + private static final Map<String, ATSAttributes> WORK_ITEM_ID_TO_ATS_ATTRIBUTE_MAP = + new HashMap<String, ATSAttributes>(); + + // @formatter:off + public static final ATSAttributes WORKING_BRANCH_WIDGET = new ATSAttributes("Working Branch"); + public static final ATSAttributes VALIDATE_REQ_CHANGES_WIDGET = new ATSAttributes("Validate Requirement Changes"); + public static final ATSAttributes CREATE_CODE_TEST_TASKS_OFF_REQUIREMENTS = new ATSAttributes("Create Code/Test Tasks"); + public static final ATSAttributes CHECK_SIGNALS_VIA_CDB_WIDGET = new ATSAttributes("Check Signals Via CDB"); + public static final ATSAttributes SHOW_CDB_DIFF_REPORT_WIDGET = new ATSAttributes("Show CDB Differences Report"); + public static final ATSAttributes COMMIT_MANAGER_WIDGET = new ATSAttributes("Commit Manager", "Commit branches to parent and parallel branches."); + // @formatter:on + + private final String displayName; + private final String description; + private final String workItemId; + + protected ATSAttributes(String displayName, String workItemId, String description) { + this.displayName = displayName; + this.workItemId = workItemId; + this.description = description; + WORK_ITEM_ID_TO_ATS_ATTRIBUTE_MAP.put(workItemId, this); + } + + private ATSAttributes(String displayName) { + this(displayName, ""); + } + + private ATSAttributes(String displayName, String description) { + this(displayName, "ats." + displayName, description); + } + + public static ATSAttributes getAtsAttributeByStoreName(String workItemId) { + return WORK_ITEM_ID_TO_ATS_ATTRIBUTE_MAP.get(workItemId); + } + + @Override + public final boolean equals(Object obj) { + return super.equals(obj); + } + + @Override + public final int hashCode() { + return super.hashCode(); + } + + public String getDisplayName() { + return displayName; + } + + public String getWorkItemId() { + return workItemId; + } + + public String getDescription() { + return description; + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsArtifactTypes.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsArtifactTypes.java new file mode 100644 index 00000000000..de0fff009bc --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsArtifactTypes.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.type; + +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.data.TokenFactory; + +public final class AtsArtifactTypes { + + // @formatter:off + public static final IArtifactType Action = TokenFactory.createArtifactType("AAMFDhY_rns71KvX14QA", "Action"); + public static final IArtifactType ActionableItem = TokenFactory.createArtifactType("AAMFDhW2LmhtRFsVyzwA", "Actionable Item"); + public static final IArtifactType DecisionReview = TokenFactory.createArtifactType("AAMFDhfrdR7BGTL7H_wA", "Decision Review"); + public static final IArtifactType PeerToPeerReview = TokenFactory.createArtifactType("AAMFDhh_300dpgmNtRAA", "PeerToPeer Review"); + public static final IArtifactType Task = TokenFactory.createArtifactType("AAMFDhbTAAB6h+06fuAA", "Task"); + public static final IArtifactType AbstractWorkflowArtifact = TokenFactory.createArtifactType("ABMfXC+LFBn31ZZbvjAA", "Abstract State Machine Artifact"); + public static final IArtifactType ReviewArtifact = TokenFactory.createArtifactType("ABMa6P4TwzXA1b8K3RAA", "Abstract Review Artifact"); + public static final IArtifactType TeamDefinition = TokenFactory.createArtifactType("AAMFDhUrlytusKbaQGAA", "Team Definition"); + public static final IArtifactType TeamWorkflow = TokenFactory.createArtifactType("AAMFDhSiF2OD+wiUqugA", "Team Workflow"); + public static final IArtifactType Version = TokenFactory.createArtifactType("AAMFDhder0oETnv14xQA", "Version"); + public static final IArtifactType Goal = TokenFactory.createArtifactType("ABMgU119UjI_Q23Yu+gA", "Goal"); + public static final IArtifactType AtsArtifact = TokenFactory.createArtifactType("ABMaLS0jvw92SE+4ZJQA", "ats.Ats Artifact"); + public static final IArtifactType WorkDefinition = TokenFactory.createArtifactType("AGrU8fWa3AJ6uoWYP7wA", "Work Definition"); + // @formatter:on + + private AtsArtifactTypes() { + // Constants + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsAttributeTypes.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsAttributeTypes.java new file mode 100644 index 00000000000..5b836a925c9 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsAttributeTypes.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.type; + +import java.util.HashMap; +import java.util.Map; +import org.eclipse.osee.framework.core.data.IAttributeType; +import org.eclipse.osee.framework.core.data.TokenFactory; +import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; + +/** + * @author Ryan D. Brooks + * @author Donald G. Dunne + */ +public final class AtsAttributeTypes { + + public static final Map<String, IAttributeType> nameToTypeMap = new HashMap<String, IAttributeType>(); + // @formatter:off + public static final IAttributeType Actionable = createType("AAMFEcvDtBiaJ3TMatAA", "Actionable", "True if item can have Action written against or assigned to."); + public static final IAttributeType ActionableItem = createType("AAMFEdbcR2zpGzFOLOQA", "Actionable Item", "Actionable Items that are impacted by this change."); + public static final IAttributeType ActionDetailsFormat = createType("Aij_PfM7wCsEA2Z720wA", "Action Details Format", "Format of string when push Action Details Copy button on SMA Workflow Editor."); + public static final IAttributeType Active = createType("AAMFEclQOVmzkIvzyWwA", "Active", "Active ATS configuration object."); + public static final IAttributeType AllowCommitBranch = createType("AAMFEbCZCkwgj73BsQgA", "Allow Commit Branch"); + public static final IAttributeType AllowCreateBranch = createType("AAMFEbARuQEvi6rtY5gA", "Allow Create Branch"); + public static final IAttributeType BaselineBranchGuid = createType("AAMFEdIjJ2za2fblEVgA", "Baseline Branch Guid", "Basline branch associated with ATS object."); + public static final IAttributeType BlockingReview = createType("AAMFEctKkjMRrIy1C7gA", "Blocking Review"); + + public static final IAttributeType Category1 = createType("AAMFEdrYniOQYrYUKKQA", "Category", "Open field for user to be able to enter text to use for categorizing/sorting."); + public static final IAttributeType Category2 = createType("AAMFEdthBkolbJKLXuAA", "Category2", Category1.getDescription()); + public static final IAttributeType Category3 = createType("AAMFEd06oxr8LMzZxdgA", "Category3", Category1.getDescription()); + + public static final IAttributeType ChangeType = createType("AAMFEc+MwGHnPCv7HlgA", "Change Type", "Type of change."); + + public static final IAttributeType CancelledDate = createType("AXnyKG1waCcPPHHGEFQA", "Cancelled Date", "Date the workflow was cancelled."); + public static final IAttributeType CancelledBy = createType("AXpNsieBHnqaJJfduGgA", "Cancelled By", "UserId of the user who cancelled workflow."); + public static final IAttributeType CancelledReason = createType("AXqJE0SmwRQzvzlqC9gA", "Cancelled Reason", "Explanation of why worklfow was cancelled."); + public static final IAttributeType CancelledFromState = createType("AXrxlXOwGiAnlaUNX6AA", "Cancelled From State", "State workflow was in when cancelled."); + + public static final IAttributeType CreatedDate = createType("AXny90bBpmfNkLpNhqwA", "Created Date", "Date the workflow was created."); + public static final IAttributeType CreatedBy = createType("AXpTVIExV1p0kp9IKKQA", "Created By", "UserId of the user who created the workflow."); + + public static final IAttributeType CompletedDate = createType("AXnxSfRg6UhirNzaZnQA", "Completed Date", "Date the workflow was completed."); + public static final IAttributeType CompletedBy = createType("AXo6tqxrOStgd9P16XQA", "Completed By", "UserId of the user who completed workflow."); + public static final IAttributeType CompletedFromState = createType("AXr9OO909xRiI3MFNOwA", "Completed From State", "State workflow was in when completed."); + + public static final IAttributeType CurrentState = createType("AAMFEdOWL3u6hmX2VbwA", "Current State", "Current state of workflow state machine."); + public static final IAttributeType CurrentStateType = createType("ATOWheEyGUJmPmPuqyAA", "Current State Type", "Type of Current State: InWork, Completed or Cancelled."); + public static final IAttributeType Decision = createType("AAMFEd7uDXcmqq_FrCQA", "Decision", "Option selected during decision review."); + + public static final IAttributeType DecisionReviewOptions = createType("AAMFEd5hRy1+SRJRqfwA", "Decision Review Options", "Options available for selection in review. Each line is a separate option. Format: <option name>;<state to transition to>;<assignee>"); + public static final IAttributeType Description = createType("AAMFEdWJ_ChxX6+YKbwA", "Description", "Detailed explanation."); + public static final IAttributeType DslSheet = createType("AGrqojZDowPDaLh4kBAA", "DSL Sheet", "XText DSL Sheet for ATS"); + public static final IAttributeType EstimatedCompletionDate = createType("AAMFEc18k3Gh+GP7zqAA", "Estimated Completion Date", "Date the changes will be completed."); + public static final IAttributeType EstimatedHours = createType("AAMFEdCSqBh+cPyadiwA", "Estimated Hours", "Hours estimated to implement the changes associated with this Action.\nIncludes estimated hours for workflows, tasks and reviews."); + public static final IAttributeType EstimatedReleaseDate = createType("AAMFEcy6VB7Ble5SP1QA", "Estimated Release Date", "Date the changes will be made available to the users."); + public static final IAttributeType FullName = createType("AAMFEdZI9XLT34cTonAA", "Full Name", "Expanded and descriptive name."); + public static final IAttributeType GoalOrderVote = createType("Aiecsz9pP1CRoQdaYRAA", "Goal Order Vote", "Vote for order item belongs to within goal."); + public static final IAttributeType HoursPerWorkDay = createType("AAMFEdGlqFsZp22RMdAA", "Hours Per Work Day"); + public static final IAttributeType LegacyPcrId = createType("AAMFEd3TakphMtQX1zgA", "Legacy PCR Id", "Field to register problem change report id from legacy items imported into ATS."); + public static final IAttributeType Location = createType("AAMFEeAW4QBlesdfacwA", "Location", "Enter location of materials to review."); + public static final IAttributeType LocChanged= createType("AQR27biJiQlOKTEKCvwA", "LOC Changed", "Total Lines of Code Changed"); + public static final IAttributeType LocReviewed = createType("AQR5ckRsrh4PpayYGAgA", "LOC Reviewed", "Total Lines of Code Reviewed"); + public static final IAttributeType Log = createType("AAMFEdgB1DX3eJSZb0wA", "Log"); + + public static final IAttributeType MeetingLocation = createType("APom8wytSX0G3mcb3qQA", "Meeting Location", "Location meeting is held."); + public static final IAttributeType MeetingAttendee = createType("APrZQQaOlFcX1CxbO6QA", "Meeting Attendee", "Attendee of meeting."); + public static final IAttributeType MeetingLength = createType("APoxOFjXzV49ZmO3CfwA", "Meeting Length", "Length of meeting."); + + public static final IAttributeType NeedBy = createType("AAMFEcxAGzHAKfDNAIwA", "Need By", "Hard schedule date that workflow must be completed."); + public static final IAttributeType NextVersion = createType("AAMFEcpH8Xb72hsF5AwA", "Next Version", "True if version artifact is \"Next\" version to be released."); + public static final IAttributeType Numeric1 = createType("AABY2xxQsDm811kCViwA", "Numeric1", "Open field for user to be able to enter numbers for sorting."); + public static final IAttributeType Numeric2 = createType("AABiRtvZsAEkU4BS9qwA", "Numeric2", Numeric1.getDescription()); + public static final IAttributeType OperationalImpact = createType("ADTfjCBpFxlyV3o1wLwA", "Operational Impact"); + public static final IAttributeType OperationalImpactDescription = createType("ADTfjCDvUF5PtiKdQ3wA", "Operational Impact Description"); + public static final IAttributeType OperationalImpactWorkaround = createType("AbMqFfIwQHRbmzT_VTAA", "Operational Impact Workaround"); + public static final IAttributeType OperationalImpactWorkaroundDescription = createType("AbMo7PoIukFDhQFJxKwA", "Operational Impact Workaround Description"); + public static final IAttributeType PagesChanged= createType("AQR8yMuv4W84UwvSJAQA", "Pages Changed", "Total Pages of Changed"); + public static final IAttributeType PagesReviewed = createType("AQR9qM8TTyCMb7sf4cQA", "Pages Reviewed", "Total Pages Reviewed"); + public static final IAttributeType PercentRework = createType("AAMFEdKfjl2TII9+tuwA", "Percent Rework"); + public static final IAttributeType PercentComplete = createType("AALLbOZiBBDN39YsRSAA", "Percent Complete"); + + public static final IAttributeType Points = createType("AY2EeqhzcDEGtXtREkAA", "Points", "Abstract value that describes risk, complexity, and size of Actions."); + public static final IAttributeType PriorityType = createType("AAMFEc8JzH1U6XGD59QA", "Priority", "1 = High; 5 = Low"); + public static final IAttributeType Problem = createType("AAMFEdQUxRyevvTu+bwA", "Problem", "Problem found during analysis."); + public static final IAttributeType ProposedResolution = createType("AAMFEdSSRDGgBQ5tctAA", "Proposed Resolution", "Recommended resolution."); + public static final IAttributeType RelatedToState = createType("AAMFEdkwHULOmHbMbGgA", "Related To State", "State of parent workflow this object is related to."); + public static final IAttributeType Released = createType("AAMFEcnMoUZMLA2zB1AA", "Released", "True if object is in a released state."); + public static final IAttributeType ReleaseDate = createType("AAMFEc3+cGcMDOCdmdAA", "Release Date", "Date the changes were made available to the users."); + public static final IAttributeType Resolution = createType("AAMFEdUMfV1KdbQNaKwA", "Resolution", "Implementation details."); + public static final IAttributeType ReviewBlocks = createType("AAMFEc6G2A8jmRWJgagA", "Review Blocks", "Review Completion will block it's parent workflow in this manner."); + public static final IAttributeType ReviewDefect = createType("AAMFEd+MSVAb8JQ6f5gA", "Review Defect"); + public static final IAttributeType ReviewFormalType = createType("AOwrClAkonFC_UKqyJAA", "Review Formal Type"); + public static final IAttributeType Role = createType("AAMFEeCqMz0XCSBJ+IQA", "Role"); + public static final IAttributeType RuleDefinition = createType("AEqAJNnkyW4_d5_WhpgA", "Rule Definition"); + public static final IAttributeType SmaNote = createType("AAMFEdm7ywte8qayfbAA", "SMA Note", "Notes applicable to ATS object"); + public static final IAttributeType State = createType("AAMFEdMa3wzVvp60xLQA", "State", "States of workflow state machine."); + public static final IAttributeType StateNotes = createType("AAMFEdiWPm7M_xV1EswA", "State Notes"); + public static final IAttributeType TeamDefinition = createType("AAMFEdd5bFEe18bd0lQA", "Team Definition"); + public static final IAttributeType TeamUsesVersions = createType("AAMFEcrHnzPxQ7w3ligA", "Team Uses Versions", "True if Team Workflow uses versioning/releasing option."); + public static final IAttributeType Title = createType(CoreAttributeTypes.Name.getGuid(), CoreAttributeTypes.Name.getName(), "Enter clear and consise title that can be generally understood."); + public static final IAttributeType UserCommunity = createType("AAMFEdAPtAq1IEwiCQAA", "User Community", "If working in one of these communities resulted in the creation of this Action, please select. Otherwise, select Other."); + public static final IAttributeType ValidationRequired = createType("AAMFEcjT0TwkD2R4w1QA", "Validation Required", "If selected, originator will be asked to validate the implementation."); + public static final IAttributeType VersionLocked = createType("AAzRtEJXbjzR5jySOZgA", "Version Locked", "True if version artifact is locked."); + public static final IAttributeType WeeklyBenefit = createType("AAMFEdEnEU9AecOHMOwA", "Weekly Benefit", "Estimated number of hours that will be saved over a single year if this change is completed."); + public static final IAttributeType WorkflowDefinitionOld = createType("ADG50fkFrQIxmfZgk3gA", "Workflow Definition Old", "Used in 0.9.8 - Unused in 0.9.9 - Specific work flow definition id used by this Workflow artifact"); + public static final IAttributeType WorkflowDefinition = createType("AbksV06OrBP_ceKCeSQA", "Workflow Definition", "Specific work flow definition id used by this Workflow artifact"); + public static final IAttributeType RelatedTaskWorkflowDefinitionOld = createType("AdR02A0xcUq4arK58BAA", "Used in 0.9.8 - Unused in 0.9.9 - Related Task Workflow Definition", "Specific work flow definition id used by Tasks related to this Workflow"); + public static final IAttributeType RelatedTaskWorkDefinition = createType("AblApNMuhjVuyDRq6VgA", "Related Task Workflow Definition", "Specific work flow definition id used by Tasks related to this Workflow"); + public static final IAttributeType WorkPackage = createType("AAMFEdpJqRp2wvA2qvAA", "Work Package", "Designated accounting work package for completing workflow."); + + + // @formatter:on + + private static IAttributeType createType(String guid, String name) { + IAttributeType type = TokenFactory.createAttributeType(guid, "ats." + name); + nameToTypeMap.put(type.getName(), type); + return type; + } + + private static IAttributeType createType(String guid, String name, String description) { + IAttributeType type = TokenFactory.createAttributeType(guid, "ats." + name, description); + nameToTypeMap.put(type.getName(), type); + return type; + } + + public static IAttributeType getTypeByName(String name) { + return nameToTypeMap.get(name); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsRelationTypes.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsRelationTypes.java new file mode 100644 index 00000000000..14f5b858262 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/type/AtsRelationTypes.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.type; + +import org.eclipse.osee.framework.core.data.IRelationTypeSide; +import org.eclipse.osee.framework.core.data.TokenFactory; +import org.eclipse.osee.framework.core.enums.RelationSide; + +/** + * @author Donald G. Dunne + */ +public final class AtsRelationTypes { + + public static final IRelationTypeSide ActionToWorkflow_Action = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE953ixQThusHUPwA", "ActionToWorkflow"); + public static final IRelationTypeSide ActionToWorkflow_WorkFlow = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE953ixQThusHUPwA", "ActionToWorkflow"); + public static final IRelationTypeSide FavoriteUser_Artifact = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE+NegDLK1g2ph+AA", "FavoriteUser"); + public static final IRelationTypeSide FavoriteUser_User = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "AAMFE+NegDLK1g2ph+AA", "FavoriteUser"); + public static final IRelationTypeSide Goal_Goal = TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, + "ABMn0wPKdyN+Mfo5nwgA", "Goal"); + public static final IRelationTypeSide Goal_Member = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "ABMn0wPKdyN+Mfo5nwgA", "Goal"); + public static final IRelationTypeSide ParallelVersion_Child = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE_EJHSBGb9msPXQA", "ParallelVersion"); + public static final IRelationTypeSide ParallelVersion_Parent = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE_EJHSBGb9msPXQA", "ParallelVersion"); + public static final IRelationTypeSide PrivilegedMember_Member = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE9XfiibyK1x2FiwA", "PrivilegedMember"); + public static final IRelationTypeSide PrivilegedMember_Team = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE9XfiibyK1x2FiwA", "PrivilegedMember"); + public static final IRelationTypeSide SmaToTask_Sma = TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, + "AAMFE97xw1BM5l+GxKAA", "SmaToTask"); + public static final IRelationTypeSide SmaToTask_Task = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "AAMFE97xw1BM5l+GxKAA", "SmaToTask"); + public static final IRelationTypeSide SubscribedUser_Artifact = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE+LkSAkfUWoTHdwA", "SubscribedUser"); + public static final IRelationTypeSide SubscribedUser_User = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "AAMFE+LkSAkfUWoTHdwA", "SubscribedUser"); + public static final IRelationTypeSide TeamActionableItem_ActionableItem = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE939Ul9Oenq9wWgA", "TeamActionableItem"); + public static final IRelationTypeSide TeamActionableItem_Team = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE939Ul9Oenq9wWgA", "TeamActionableItem"); + public static final IRelationTypeSide TeamDefinitionToDecisionReviewWorkflowDiagram_TeamDefinition = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, "AAMFE+Fg4RmKrda_jJQA", + "TeamDefinitionToDecisionReviewWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToDecisionReviewWorkflowDiagram_WorkflowDiagram = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, "AAMFE+Fg4RmKrda_jJQA", + "TeamDefinitionToDecisionReviewWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToPeerToPeerReviewWorkflowDiagram_TeamDefinition = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, "AAMFE+HqYUG262IxMFwA", + "TeamDefinitionToPeerToPeerReviewWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToPeerToPeerReviewWorkflowDiagram_WorkflowDiagram = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, "AAMFE+HqYUG262IxMFwA", + "TeamDefinitionToPeerToPeerReviewWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToTaskWorkflowDiagram_TeamDefinition = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, "AAMFE+DkeQ9mRBPca0QA", + "TeamDefinitionToTaskWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToTaskWorkflowDiagram_WorkflowDiagram = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, "AAMFE+DkeQ9mRBPca0QA", + "TeamDefinitionToTaskWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToVersion_TeamDefinition = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE9_i7zG3lR1kGWQA", "TeamDefinitionToVersion"); + public static final IRelationTypeSide TeamDefinitionToVersion_Version = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE9_i7zG3lR1kGWQA", "TeamDefinitionToVersion"); + public static final IRelationTypeSide TeamDefinitionToWorkflowDiagram_TeamDefinition = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, "AAMFE+BpKTGewbN8c3gA", + "TeamDefinitionToWorkflowDiagram"); + public static final IRelationTypeSide TeamDefinitionToWorkflowDiagram_WorkflowDiagram = + TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, "AAMFE+BpKTGewbN8c3gA", + "TeamDefinitionToWorkflowDiagram"); + public static final IRelationTypeSide TeamLead_Lead = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "AAMFE90HyTZPyHuQWOQA", "TeamLead"); + public static final IRelationTypeSide TeamLead_Team = TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, + "AAMFE90HyTZPyHuQWOQA", "TeamLead"); + public static final IRelationTypeSide TeamMember_Member = TokenFactory.createRelationTypeSide(RelationSide.SIDE_B, + "AAMFE92A6gCO9WJ2ijQA", "TeamMember"); + public static final IRelationTypeSide TeamMember_Team = TokenFactory.createRelationTypeSide(RelationSide.SIDE_A, + "AAMFE92A6gCO9WJ2ijQA", "TeamMember"); + public static final IRelationTypeSide TeamWorkflowTargetedForVersion_Version = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE99pzm4zSibDT9gA", "TeamWorkflowTargetedForVersion"); + public static final IRelationTypeSide TeamWorkflowTargetedForVersion_Workflow = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE99pzm4zSibDT9gA", "TeamWorkflowTargetedForVersion"); + public static final IRelationTypeSide TeamWorkflowToReview_Review = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_B, "AAMFE+JqDz+8tuRDdIwA", "TeamWorkflowToReview"); + public static final IRelationTypeSide TeamWorkflowToReview_Team = TokenFactory.createRelationTypeSide( + RelationSide.SIDE_A, "AAMFE+JqDz+8tuRDdIwA", "TeamWorkflowToReview"); + + private AtsRelationTypes() { + // Constants + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsCacheManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsCacheManager.java new file mode 100644 index 00000000000..bffcea6ddf8 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsCacheManager.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.config.ActionableItemArtifact; +import org.eclipse.osee.ats.core.config.AtsBulkLoad; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.task.TaskArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.enums.Active; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactCache; +import org.eclipse.osee.framework.skynet.core.event.OseeEventManager; +import org.eclipse.osee.framework.skynet.core.event.filter.IEventFilter; +import org.eclipse.osee.framework.skynet.core.event.listener.IArtifactEventListener; +import org.eclipse.osee.framework.skynet.core.event.model.ArtifactEvent; +import org.eclipse.osee.framework.skynet.core.event.model.EventBasicGuidArtifact; +import org.eclipse.osee.framework.skynet.core.event.model.EventBasicGuidRelation; +import org.eclipse.osee.framework.skynet.core.event.model.EventModType; +import org.eclipse.osee.framework.skynet.core.event.model.Sender; +import org.eclipse.osee.framework.skynet.core.utility.DbUtil; + +/** + * Common cache storage for ATS configuration artifacts:<br> + * TeamDefinitionArtifact<br> + * VersionArtifact<br> + * ActionableItemArtifact<br> + * All other artifact types will silently not cached<br> + * + * @author Donald G. Dunne + */ +public class AtsCacheManager implements IArtifactEventListener { + + private static Map<AbstractTaskableArtifact, Collection<TaskArtifact>> teamTasksCache = + new HashMap<AbstractTaskableArtifact, Collection<TaskArtifact>>(); + + public static void start() { + new AtsCacheManager(); + } + + private AtsCacheManager() { + OseeEventManager.addPriorityListener(this); + } + + public static synchronized void decacheTaskArtifacts(AbstractTaskableArtifact sma) { + teamTasksCache.remove(sma); + } + + public static synchronized Collection<TaskArtifact> getTaskArtifacts(AbstractTaskableArtifact sma) throws OseeCoreException { + if (!teamTasksCache.containsKey(sma)) { + Collection<TaskArtifact> taskArtifacts = + sma.getRelatedArtifacts(AtsRelationTypes.SmaToTask_Task, TaskArtifact.class); + if (taskArtifacts.isEmpty()) { + return taskArtifacts; + } + teamTasksCache.put(sma, taskArtifacts); + } + return teamTasksCache.get(sma); + } + + public static List<Artifact> getArtifactsByName(IArtifactType artifactType, String name) { + AtsBulkLoad.loadConfig(true); + return ArtifactCache.getArtifactsByName(artifactType, name); + } + + public static ActionableItemArtifact getActionableItemByGuid(String guid) throws OseeCoreException { + AtsBulkLoad.loadConfig(true); + return (ActionableItemArtifact) ArtifactCache.getActive(guid, AtsUtilCore.getAtsBranch().getId()); + } + + public static TeamDefinitionArtifact getTeamDefinitionArtifact(String guid) throws OseeCoreException { + AtsBulkLoad.loadConfig(true); + return (TeamDefinitionArtifact) ArtifactCache.getActive(guid, AtsUtilCore.getAtsBranch().getId()); + } + + public static List<Artifact> getArtifactsByActive(IArtifactType artifactType, Active active) throws OseeCoreException { + AtsBulkLoad.loadConfig(true); + return AtsUtilCore.getActive(ArtifactCache.getArtifactsByType(artifactType), active, null); + } + + public static Artifact getSoleArtifactByName(IArtifactType artifactType, String name) { + AtsBulkLoad.loadConfig(true); + List<Artifact> arts = ArtifactCache.getArtifactsByName(artifactType, name); + if (arts.size() == 1) { + return arts.iterator().next(); + } + return null; + } + + @Override + public void handleArtifactEvent(ArtifactEvent artifactEvent, Sender sender) { + if (DbUtil.isDbInit()) { + OseeEventManager.removeListener(this); + return; + } + processArtifacts(artifactEvent); + processRelations(artifactEvent); + } + + private void processRelations(ArtifactEvent artifactEvent) { + for (EventBasicGuidRelation guidRel : artifactEvent.getRelations()) { + try { + if (guidRel.is(AtsRelationTypes.SmaToTask_Task)) { + for (TaskArtifact taskArt : ArtifactCache.getActive(guidRel, TaskArtifact.class)) { + teamTasksCache.remove(taskArt.getParent()); + } + for (Artifact artifact : ArtifactCache.getActive(guidRel)) { + if (artifact instanceof AbstractTaskableArtifact) { + teamTasksCache.remove(artifact); + } + } + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + } + + private void processArtifacts(ArtifactEvent artifactEvent) { + for (EventBasicGuidArtifact guidArt : artifactEvent.getArtifacts()) { + try { + if (guidArt.is(EventModType.Deleted, EventModType.Purged)) { + if (guidArt.is(AtsArtifactTypes.Task) && guidArt.is(EventModType.Deleted)) { + Artifact artifact = ArtifactCache.getActive(guidArt); + if (artifact != null) { + teamTasksCache.remove(artifact.getParent()); + } + } + Artifact artifact = ArtifactCache.getActive(guidArt); + if (artifact instanceof AbstractTaskableArtifact) { + teamTasksCache.remove(artifact); + } + } + if (guidArt.is(EventModType.Added, EventModType.Modified)) { + // Only process if in cache + Artifact artifact = ArtifactCache.getActive(guidArt); + if (artifact != null && guidArt.is(EventModType.Added)) { + if (artifact.isOfType(AtsArtifactTypes.Task)) { + teamTasksCache.remove(artifact.getParent()); + } + if (artifact instanceof AbstractTaskableArtifact) { + teamTasksCache.remove(artifact); + } + } + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + } + + @Override + public List<? extends IEventFilter> getEventFilters() { + return Arrays.asList(OseeEventManager.getCommonBranchFilter()); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsUtilCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsUtilCore.java new file mode 100644 index 00000000000..efacf94f7cc --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/AtsUtilCore.java @@ -0,0 +1,111 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.data.IArtifactToken; +import org.eclipse.osee.framework.core.data.IOseeBranch; +import org.eclipse.osee.framework.core.enums.Active; +import org.eclipse.osee.framework.core.enums.CoreBranches; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.OseeGroup; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; + +/** + * @author Donald G. Dunne + */ +public class AtsUtilCore { + public final static double DEFAULT_HOURS_PER_WORK_DAY = 8; + private static OseeGroup atsAdminGroup = new OseeGroup("AtsAdmin"); + + /** + * TODO Remove duplicate Active flags, need to convert all ats.Active to Active in DB + * + * @param artifacts to iterate through + * @param active state to validate against; Both will return all artifacts matching type + * @param clazz type of artifacts to consider; null for all + * @return set of Artifacts of type clazz that match the given active state of the "Active" or "ats.Active" attribute + * value. If no attribute exists, Active == true; If does exist then attribute value "yes" == true, "no" == false. + */ + @SuppressWarnings("unchecked") + public static <A extends Artifact> List<A> getActive(Collection<A> artifacts, Active active, Class<? extends Artifact> clazz) throws OseeCoreException { + List<A> results = new ArrayList<A>(); + Collection<? extends Artifact> artsOfClass = + clazz != null ? Collections.castMatching(clazz, artifacts) : artifacts; + for (Artifact art : artsOfClass) { + if (active == Active.Both) { + results.add((A) art); + } else { + // assume active unless otherwise specified + boolean attributeActive = ((A) art).getSoleAttributeValue(AtsAttributeTypes.Active, false); + if (active == Active.Active && attributeActive) { + results.add((A) art); + } else if (active == Active.InActive && !attributeActive) { + results.add((A) art); + } + } + } + return results; + } + + public static boolean isAtsAdmin() { + try { + return getAtsAdminGroup().isCurrentUserMember(); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return false; + } + } + + public static OseeGroup getAtsAdminGroup() { + return atsAdminGroup; + } + + public static String doubleToI18nString(double d) { + return doubleToI18nString(d, false); + } + + public static String doubleToI18nString(double d, boolean blankIfZero) { + if (blankIfZero && d == 0) { + return ""; + } + // This enables java to use same string for all 0 cases instead of creating new one + else if (d == 0) { + return "0.00"; + } else { + return String.format("%4.2f", d); + } + } + + public static Branch getAtsBranch() throws OseeCoreException { + return BranchManager.getCommonBranch(); + } + + public static IOseeBranch getAtsBranchToken() { + return CoreBranches.COMMON; + } + + public static Artifact getFromToken(IArtifactToken token) { + Artifact toReturn = null; + try { + toReturn = ArtifactQuery.getArtifactFromToken(token, getAtsBranchToken()); + } catch (OseeCoreException ex) { + // Do Nothing; + } + return toReturn; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/WorkflowManagerCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/WorkflowManagerCore.java new file mode 100644 index 00000000000..ba70926b6fb --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/util/WorkflowManagerCore.java @@ -0,0 +1,103 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.util; + +import java.util.Collection; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.workdef.RuleDefinitionOption; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.StateManager; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; + +/** + * @author Donald G. Dunne + */ +public class WorkflowManagerCore { + + public static StateManager getStateManager(Artifact artifact) { + return cast(artifact).getStateMgr(); + } + + public static AbstractWorkflowArtifact cast(Artifact artifact) { + if (artifact instanceof AbstractWorkflowArtifact) { + return (AbstractWorkflowArtifact) artifact; + } + return null; + } + + public static boolean isEditable(AbstractWorkflowArtifact sma, StateDefinition stateDef, boolean priviledgedEditEnabled) throws OseeCoreException { + // must be writeable + return !sma.isReadOnly() && + // and access control writeable + sma.isAccessControlWrite() && + // and current state + (stateDef == null || sma.isInState(stateDef)) && + // and one of these + // + // page is define to allow anyone to edit + (sma.getStateDefinition().hasRule(RuleDefinitionOption.AllowEditToAll) || + // team definition has allowed anyone to edit + sma.teamDefHasRule(RuleDefinitionOption.AllowEditToAll) || + // priviledged edit mode is on + priviledgedEditEnabled || + // current user is assigned + sma.isAssigneeMe() || + // current user is ats admin + AtsUtilCore.isAtsAdmin()); + } + + public static AbstractWorkflowArtifact getParentAWA(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Task)) { + Collection<Artifact> awas = artifact.getRelatedArtifacts(AtsRelationTypes.SmaToTask_Sma); + if (awas.isEmpty()) { + throw new OseeStateException("Task has no parent [%s]", artifact.getHumanReadableId()); + } + return (AbstractWorkflowArtifact) awas.iterator().next(); + } else if (artifact.isOfType(AtsArtifactTypes.ReviewArtifact)) { + Collection<Artifact> awas = artifact.getRelatedArtifacts(AtsRelationTypes.TeamWorkflowToReview_Team); + if (!awas.isEmpty()) { + return (AbstractWorkflowArtifact) awas.iterator().next(); + } + } + return null; + } + + public static Artifact getTeamDefinition(Artifact artifact) throws OseeCoreException { + Artifact team = getParentTeamWorkflow(artifact); + if (team != null) { + String teamDefGuid = team.getSoleAttributeValue(AtsAttributeTypes.TeamDefinition); + return ArtifactQuery.getArtifactFromId(teamDefGuid, BranchManager.getCommonBranch()); + } + return null; + } + + public static Artifact getParentActionArtifact(Artifact artifact) throws OseeCoreException { + Artifact team = getParentTeamWorkflow(artifact); + if (team != null) { + return artifact.getRelatedArtifact(AtsRelationTypes.ActionToWorkflow_Action); + } + return null; + } + + public static Artifact getParentTeamWorkflow(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.TeamWorkflow)) { + return artifact; + } else if (artifact.isOfType(AtsArtifactTypes.Task)) { + return getParentAWA(artifact); + } else if (artifact.isOfType(AtsArtifactTypes.ReviewArtifact)) { + return getParentAWA(artifact); + } + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/TargetedVersionUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/TargetedVersionUtil.java new file mode 100644 index 00000000000..45406010a77 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/TargetedVersionUtil.java @@ -0,0 +1,78 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.version; + +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; + +/** + * @author Donald G. Dunne + */ +public class TargetedVersionUtil { + + public static VersionArtifact getTargetedVersion(Object object) throws OseeCoreException { + if (object instanceof AbstractWorkflowArtifact) { + TeamWorkFlowArtifact teamArt = ((AbstractWorkflowArtifact) object).getParentTeamWorkflow(); + if (teamArt != null) { + if (teamArt.getRelatedArtifactsCount(AtsRelationTypes.TeamWorkflowTargetedForVersion_Version) > 0) { + List<Artifact> verArts = + teamArt.getRelatedArtifacts(AtsRelationTypes.TeamWorkflowTargetedForVersion_Version); + if (verArts.size() > 1) { + OseeLog.log(Activator.class, Level.SEVERE, + "Multiple targeted versions for artifact " + teamArt.toStringWithId()); + return (VersionArtifact) verArts.iterator().next(); + } else { + return (VersionArtifact) verArts.iterator().next(); + } + } + } + } + return null; + } + + public static String getTargetedVersionStr(Object object) throws OseeCoreException { + if (object instanceof AbstractWorkflowArtifact) { + TeamWorkFlowArtifact teamArt = ((AbstractWorkflowArtifact) object).getParentTeamWorkflow(); + if (teamArt != null) { + Collection<Artifact> verArts = + teamArt.getRelatedArtifacts(AtsRelationTypes.TeamWorkflowTargetedForVersion_Version); + if (verArts.isEmpty()) { + return ""; + } + if (verArts.size() > 1) { + String errStr = + "Workflow " + teamArt.getHumanReadableId() + " targeted for multiple versions: " + Artifacts.commaArts(verArts); + OseeLog.log(Activator.class, Level.SEVERE, errStr, null); + return "!Error " + errStr; + } + Artifact verArt = verArts.iterator().next(); + if (!teamArt.isCompleted() && !teamArt.isCancelled() && verArt.getSoleAttributeValue( + AtsAttributeTypes.Released, false)) { + String errStr = + "Workflow " + teamArt.getHumanReadableId() + " targeted for released version, but not completed: " + verArt; + if (!teamArt.isTargetedErrorLogged()) { + OseeLog.log(Activator.class, Level.SEVERE, errStr, null); + teamArt.setTargetedErrorLogged(true); + } + return "!Error " + errStr; + } + return verArt.getName(); + } + } + return ""; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionArtifact.java new file mode 100644 index 00000000000..82ea2de73fd --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionArtifact.java @@ -0,0 +1,163 @@ +/* + * Created on Mar 24, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.version; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.commit.ICommitConfigArtifact; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.ArtifactDoesNotExist; +import org.eclipse.osee.framework.core.exception.BranchDoesNotExist; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.jdk.core.util.GUID; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; + +public class VersionArtifact extends org.eclipse.osee.framework.skynet.core.artifact.Artifact implements ICommitConfigArtifact { + + public VersionArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + public TeamDefinitionArtifact getParentTeamDefinition() throws OseeCoreException { + return this.getRelatedArtifacts(AtsRelationTypes.TeamDefinitionToVersion_TeamDefinition, + TeamDefinitionArtifact.class).iterator().next(); + } + + public void getParallelVersions(Set<ICommitConfigArtifact> configArts) throws OseeCoreException { + configArts.add(this); + for (VersionArtifact childArt : this.getRelatedArtifacts(AtsRelationTypes.ParallelVersion_Child, + VersionArtifact.class)) { + childArt.getParallelVersions(configArts); + } + } + + public Collection<TeamWorkFlowArtifact> getTargetedForTeamArtifacts() throws OseeCoreException { + return this.getRelatedArtifacts(AtsRelationTypes.TeamWorkflowTargetedForVersion_Workflow, + TeamWorkFlowArtifact.class); + } + + public void ensureVersionArtifact() throws OseeCoreException { + if (!this.isOfType(AtsArtifactTypes.Version)) { + throw new OseeArgumentException("Artifact should be Version not [%s]", this.getArtifactTypeName()); + } + } + + public Boolean isVersionLocked() throws OseeCoreException { + return this.getSoleAttributeValue(AtsAttributeTypes.VersionLocked, false); + } + + public void setVersionLocked(boolean locked) throws OseeCoreException { + this.setSoleAttributeValue(AtsAttributeTypes.VersionLocked, locked); + } + + public Boolean isNextVersion() throws OseeCoreException { + return this.getSoleAttributeValue(AtsAttributeTypes.NextVersion, false); + } + + public void setNextVersion(boolean nextVersion) throws OseeCoreException { + this.setSoleAttributeValue(AtsAttributeTypes.NextVersion, nextVersion); + } + + public Boolean isReleased() throws OseeCoreException { + return this.getSoleAttributeValue(AtsAttributeTypes.Released, false); + } + + public void setReleased(boolean released) throws OseeCoreException { + this.setSoleAttributeValue(AtsAttributeTypes.Released, released); + } + + public TeamDefinitionArtifact getTeamDefinitionArtifact() throws OseeCoreException { + try { + return (TeamDefinitionArtifact) this.getRelatedArtifact(AtsRelationTypes.TeamDefinitionToVersion_TeamDefinition); + } catch (ArtifactDoesNotExist ex) { + return null; + } + } + + public Branch getBaselineBranch() throws OseeCoreException { + String branchGuid = this.getSoleAttributeValue(AtsAttributeTypes.BaselineBranchGuid, ""); + if (Strings.isValid(branchGuid)) { + return BranchManager.getBranchByGuid(branchGuid); + } else { + return getTeamDefinitionArtifact().getTeamBranch(); + } + } + + @Override + public Result isCreateBranchAllowed() throws OseeCoreException { + if (!getSoleAttributeValue(AtsAttributeTypes.AllowCreateBranch, false)) { + return new Result(false, "Branch creation disabled for Version [" + this + "]"); + } + if (getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Version [" + this + "]"); + } + return Result.TrueResult; + } + + @Override + public Result isCommitBranchAllowed() throws OseeCoreException { + if (!getSoleAttributeValue(AtsAttributeTypes.AllowCommitBranch, false)) { + return new Result(false, "Version [" + this + "] not configured to allow branch commit."); + } + if (getParentBranch() == null) { + return new Result(false, "Parent Branch not configured for Version [" + this + "]"); + } + return Result.TrueResult; + } + + @Override + public Branch getParentBranch() throws OseeCoreException { + try { + String guid = getSoleAttributeValue(AtsAttributeTypes.BaselineBranchGuid, ""); + if (GUID.isValid(guid)) { + return BranchManager.getBranchByGuid(guid); + } + } catch (BranchDoesNotExist ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return null; + } + + @Override + public String getFullDisplayName() throws OseeCoreException { + List<String> strs = new ArrayList<String>(); + if (!getName().equals(Artifact.UNNAMED)) { + strs.add(getName()); + } + String fullName = getSoleAttributeValue(AtsAttributeTypes.FullName, ""); + if (Strings.isValid(fullName)) { + strs.add(fullName); + } + String description = getSoleAttributeValue(AtsAttributeTypes.Description, ""); + if (Strings.isValid(description)) { + strs.add(description); + } + return Collections.toString(" - ", strs); + } + + @Override + public String toString() { + return getName(); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionLockedType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionLockedType.java new file mode 100644 index 00000000000..59dbf795879 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionLockedType.java @@ -0,0 +1,7 @@ +package org.eclipse.osee.ats.core.version; + +public enum VersionLockedType { + Locked, + UnLocked, + Both +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionReleaseType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionReleaseType.java new file mode 100644 index 00000000000..5f7cbd076de --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/version/VersionReleaseType.java @@ -0,0 +1,7 @@ +package org.eclipse.osee.ats.core.version; + +public enum VersionReleaseType { + Released, + UnReleased, + Both +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/AbstractWorkDefItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/AbstractWorkDefItem.java new file mode 100644 index 00000000000..e61c331b3eb --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/AbstractWorkDefItem.java @@ -0,0 +1,59 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +public class AbstractWorkDefItem { + + private String name; + protected String description; + protected Map<String, String> workDataKeyValueMap = new HashMap<String, String>(); + private final Pattern keyValuePattern = Pattern.compile("^(.*?)=(.*)$", Pattern.MULTILINE | Pattern.DOTALL); + + public AbstractWorkDefItem(String name) { + this.name = name; + } + + public String getWorkDataValue(String key) { + return workDataKeyValueMap.get(key); + } + + public void addWorkDataKeyValue(String key, String value) { + workDataKeyValueMap.put(key, value); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Pattern getKeyValuePattern() { + return keyValuePattern; + } + + public Map<String, String> getWorkDataKeyValueMap() { + return workDataKeyValueMap; + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/CompositeStateItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/CompositeStateItem.java new file mode 100644 index 00000000000..c3ed2c685ff --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/CompositeStateItem.java @@ -0,0 +1,41 @@ +/* + * Created on Dec 16, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.List; + +public class CompositeStateItem extends StateItem { + + private int numColumns; + private final List<StateItem> stateItems = new ArrayList<StateItem>(5); + + public CompositeStateItem() { + this(2); + } + + public CompositeStateItem(int numColumns) { + super("Composite"); + this.numColumns = numColumns; + } + + public int getNumColumns() { + return numColumns; + } + + public void setNumColumns(int numColumns) { + this.numColumns = numColumns; + } + + public List<StateItem> getStateItems() { + return stateItems; + } + + @Override + public String toString() { + return "Composite " + numColumns; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ConvertAtsDslToWorkDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ConvertAtsDslToWorkDefinition.java new file mode 100644 index 00000000000..adc69f95c67 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ConvertAtsDslToWorkDefinition.java @@ -0,0 +1,407 @@ +/* + * Created on Feb 15, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.emf.common.util.EList; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workdef.provider.BooleanDefUtil; +import org.eclipse.osee.ats.core.workdef.provider.UserRefUtil; +import org.eclipse.osee.ats.dsl.atsDsl.AtsDsl; +import org.eclipse.osee.ats.dsl.atsDsl.AttrWidget; +import org.eclipse.osee.ats.dsl.atsDsl.Composite; +import org.eclipse.osee.ats.dsl.atsDsl.DecisionReviewDef; +import org.eclipse.osee.ats.dsl.atsDsl.DecisionReviewOpt; +import org.eclipse.osee.ats.dsl.atsDsl.DecisionReviewRef; +import org.eclipse.osee.ats.dsl.atsDsl.FollowupRef; +import org.eclipse.osee.ats.dsl.atsDsl.LayoutCopy; +import org.eclipse.osee.ats.dsl.atsDsl.LayoutDef; +import org.eclipse.osee.ats.dsl.atsDsl.LayoutItem; +import org.eclipse.osee.ats.dsl.atsDsl.LayoutType; +import org.eclipse.osee.ats.dsl.atsDsl.PeerReviewDef; +import org.eclipse.osee.ats.dsl.atsDsl.PeerReviewRef; +import org.eclipse.osee.ats.dsl.atsDsl.StateDef; +import org.eclipse.osee.ats.dsl.atsDsl.ToState; +import org.eclipse.osee.ats.dsl.atsDsl.UserByName; +import org.eclipse.osee.ats.dsl.atsDsl.UserByUserId; +import org.eclipse.osee.ats.dsl.atsDsl.UserRef; +import org.eclipse.osee.ats.dsl.atsDsl.WidgetDef; +import org.eclipse.osee.ats.dsl.atsDsl.WidgetRef; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.type.AttributeType; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.attribute.AttributeTypeManager; +import org.eclipse.osee.framework.skynet.core.utility.AttributeTypeToXWidgetName; + +public class ConvertAtsDslToWorkDefinition { + + private final String name; + private final AtsDsl atsDsl; + + public ConvertAtsDslToWorkDefinition(String name, AtsDsl atsDsl) { + this.name = name; + this.atsDsl = atsDsl; + } + + public WorkDefinition convert() { + if (atsDsl.getWorkDef() == null) { + return null; + } + WorkDefinition workDef = new WorkDefinition(Strings.unquote(atsDsl.getWorkDef().getName())); + for (String id : atsDsl.getWorkDef().getId()) { + workDef.getIds().add(id); + } + + List<WidgetDefinition> widgetDefs = retrieveWigetDefs(atsDsl, name); + Map<StateDefinition, String> copyLayoutFromMap = new HashMap<StateDefinition, String>(); + + // Process and define all states + for (StateDef dslState : atsDsl.getWorkDef().getStates()) { + String stateName = Strings.unquote(dslState.getName()); + StateDefinition stateDef = workDef.getOrCreateState(stateName); + stateDef.setWorkDefinition(workDef); + stateDef.setDescription(dslState.getDescription()); + + // Process state settings + stateDef.setOrdinal(dslState.getOrdinal()); + WorkPageType workPageType = WorkPageType.Working; + try { + workPageType = WorkPageType.valueOf(dslState.getPageType()); + } catch (IllegalArgumentException ex) { + // do nothing + } + stateDef.setWorkPageType(workPageType); + stateDef.setPercentWeight(dslState.getPercentWeight()); + stateDef.setRecommendedPercentComplete(dslState.getRecommendedPercentComplete()); + StateColor color = StateColor.BLACK; + try { + if (Strings.isValid(dslState.getColor())) { + color = StateColor.valueOf(dslState.getColor()); + } + } catch (IllegalArgumentException ex) { + // do nothing + } + stateDef.setColor(color); + + // Process widgets + LayoutType layout = dslState.getLayout(); + if (layout instanceof LayoutDef) { + processLayoutItems(name, widgetDefs, stateDef.getStateItems(), ((LayoutDef) layout).getLayoutItems()); + } else if (layout instanceof LayoutCopy) { + copyLayoutFromMap.put(stateDef, Strings.unquote(((LayoutCopy) layout).getState().getName())); + } + + // process rules + for (String ruleName : dslState.getRules()) { + stateDef.addRule(new RuleDefinition(Strings.unquote(ruleName)), "Dsl StateDef Rule"); + } + + } + + // Process States needing layoutCopy + for (Entry<StateDefinition, String> entry : copyLayoutFromMap.entrySet()) { + StateDefinition fromStateDef = workDef.getStateByName(entry.getValue()); + StateDefinition toStateDef = entry.getKey(); + for (StateItem item : fromStateDef.getStateItems()) { + toStateDef.getStateItems().add(item); + } + } + + // Process and define all transitions + for (StateDef dslState : atsDsl.getWorkDef().getStates()) { + StateDefinition stateDef = workDef.getStateByName(Strings.unquote(dslState.getName())); + // Process transitions + for (ToState dslToState : dslState.getTransitionStates()) { + StateDefinition toStateDef = workDef.getStateByName(Strings.unquote(dslToState.getState().getName())); + stateDef.getToStates().add(toStateDef); + for (String dslTransOption : dslToState.getOptions()) { + if ("AsDefault".equals(dslTransOption)) { + stateDef.setDefaultToState(toStateDef); + } + if ("OverrideAttributeValidation".equals(dslTransOption)) { + stateDef.getOverrideAttributeValidationStates().add(toStateDef); + } + } + } + } + + // Process all decision reviews + for (StateDef dslState : atsDsl.getWorkDef().getStates()) { + StateDefinition stateDef = workDef.getStateByName(Strings.unquote(dslState.getName())); + for (DecisionReviewRef dslRevRef : dslState.getDecisionReviews()) { + DecisionReviewDef dslRevDef = dslRevRef.getDecisionReview(); + DecisionReviewDefinition revDef = convertDslDecisionReview(dslRevDef); + if (!Strings.isValid(revDef.getRelatedToState())) { + revDef.setRelatedToState(stateDef.getName()); + } + stateDef.getDecisionReviews().add(revDef); + } + } + + // Process all peer reviews + for (StateDef dslState : atsDsl.getWorkDef().getStates()) { + StateDefinition stateDef = workDef.getStateByName(Strings.unquote(dslState.getName())); + for (PeerReviewRef peerRevRef : dslState.getPeerReviews()) { + PeerReviewDef dslRevDef = peerRevRef.getPeerReview(); + PeerReviewDefinition revDef = convertDslPeerReview(dslRevDef); + if (!Strings.isValid(revDef.getRelatedToState())) { + revDef.setRelatedToState(stateDef.getName()); + } + stateDef.getPeerReviews().add(revDef); + } + } + + // Set the start state + workDef.setStartState(workDef.getStateByName(Strings.unquote(atsDsl.getWorkDef().getStartState().getName()))); + + return workDef; + } + + private DecisionReviewDefinition convertDslDecisionReview(DecisionReviewDef dslRevDef) { + DecisionReviewDefinition revDef = new DecisionReviewDefinition(dslRevDef.getName()); + revDef.setReviewTitle(dslRevDef.getTitle()); + revDef.setDescription(dslRevDef.getDescription()); + + String dslBlockType = dslRevDef.getBlockingType().getName(); + ReviewBlockType blockType = ReviewBlockType.None; + try { + blockType = ReviewBlockType.valueOf(dslBlockType); + } catch (IllegalArgumentException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("Unknown ReviewBlockType [%s]; Defaulting to None", dslBlockType)); + } + revDef.setBlockingType(blockType); + + String dslEventType = dslRevDef.getStateEvent().getName(); + StateEventType eventType = StateEventType.None; + try { + eventType = StateEventType.valueOf(dslEventType); + } catch (IllegalArgumentException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("Unknown StateEventType [%s]; Defaulting to None", dslEventType)); + } + revDef.setStateEventType(eventType); + revDef.setAutoTransitionToDecision(BooleanDefUtil.get(dslRevDef.getAutoTransitionToDecision(), false)); + + for (DecisionReviewOpt dslOpt : dslRevDef.getOptions()) { + DecisionReviewOption revOpt = new DecisionReviewOption(dslOpt.getName()); + FollowupRef followupRef = dslOpt.getFollowup(); + if (followupRef == null) { + revOpt.setFollowupRequired(false); + } else { + revOpt.getUserIds().addAll(UserRefUtil.getUserIds(followupRef.getAssigneeRefs())); + revOpt.getUserNames().addAll(UserRefUtil.getUserNames(followupRef.getAssigneeRefs())); + } + revDef.getOptions().add(revOpt); + } + + Collection<String> userIds = getAssigneesFromUserRefs(dslRevDef.getAssigneeRefs()); + revDef.getAssignees().addAll(userIds); + return revDef; + } + + private void processLayoutItems(String SHEET_NAME, List<WidgetDefinition> widgetDefs, List<StateItem> stateItems, EList<LayoutItem> layoutItems) { + for (LayoutItem layoutItem : layoutItems) { + if (layoutItem instanceof WidgetDef) { + WidgetDefinition widgetDef = convertDslWidgetDef((WidgetDef) layoutItem, SHEET_NAME); + stateItems.add(widgetDef); + } else if (layoutItem instanceof WidgetRef) { + String widgetName = Strings.unquote(((WidgetRef) layoutItem).getWidget().getName()); + boolean found = false; + for (WidgetDefinition wd : widgetDefs) { + if (wd.getName().equals(widgetName)) { + stateItems.add(wd); + found = true; + } + } + if (!found) { + OseeLog.log(Activator.class, Level.SEVERE, + String.format("Could not find WidgetRef [%s] in WidgetDefs", widgetName)); + } + } else if (layoutItem instanceof AttrWidget) { + AttrWidget attrWidget = (AttrWidget) layoutItem; + String attributeName = attrWidget.getAttributeName(); + try { + AttributeType attributeType = AttributeTypeManager.getType(attributeName); + if (attributeType == null) { + OseeLog.log(Activator.class, Level.SEVERE, + String.format("Invalid attribute name [%s] in WorkDefinition [%s]", attributeName, SHEET_NAME)); + } else { + WidgetDefinition widgetDef = new WidgetDefinition(attributeType.getUnqualifiedName()); + widgetDef.setAttributeName(attributeType.getName()); + setXWidgetNameBasedOnAttribute(attributeType, widgetDef); + extractDslWidgetDefOptions(attrWidget.getOption(), SHEET_NAME, widgetDef); + stateItems.add(widgetDef); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex, + "Error resolving attribute [%s] to WorkDefinition in [%s]", attributeName, SHEET_NAME); + } + } else if (layoutItem instanceof Composite) { + Composite composite = (Composite) layoutItem; + CompositeStateItem compStateItem = new CompositeStateItem(composite.getNumColumns()); + if (!composite.getLayoutItems().isEmpty()) { + processLayoutItems(SHEET_NAME, widgetDefs, compStateItem.getStateItems(), composite.getLayoutItems()); + } + stateItems.add(compStateItem); + } + } + + } + + private PeerReviewDefinition convertDslPeerReview(PeerReviewDef dslRevDef) { + PeerReviewDefinition revDef = new PeerReviewDefinition(dslRevDef.getName()); + revDef.setReviewTitle(dslRevDef.getTitle()); + revDef.setDescription(dslRevDef.getDescription()); + revDef.setLocation(dslRevDef.getLocation()); + + String dslBlockType = dslRevDef.getBlockingType().getName(); + ReviewBlockType blockType = ReviewBlockType.None; + try { + blockType = ReviewBlockType.valueOf(dslBlockType); + } catch (IllegalArgumentException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("Unknown ReviewBlockType [%s]; Defaulting to None", dslBlockType)); + } + revDef.setBlockingType(blockType); + + String dslEventType = dslRevDef.getStateEvent().getName(); + StateEventType eventType = StateEventType.None; + try { + eventType = StateEventType.valueOf(dslEventType); + } catch (IllegalArgumentException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("Unknown StateEventType [%s]; Defaulting to None", dslEventType)); + } + revDef.setStateEventType(eventType); + Collection<String> userIds = getAssigneesFromUserRefs(dslRevDef.getAssigneeRefs()); + revDef.getAssignees().addAll(userIds); + return revDef; + } + + private Collection<String> getAssigneesFromUserRefs(EList<UserRef> UserRefs) { + Set<String> userIds = new HashSet<String>(); + for (UserRef UserRef : UserRefs) { + if (UserRef instanceof UserByName) { + UserByName byName = (UserByName) UserRef; + String name = Strings.unquote(byName.getUserName()); + if (!Strings.isValid(name)) { + OseeLog.log(Activator.class, Level.WARNING, String.format("Unhandled UserByName name [%s]", name)); + continue; + } + try { + User user = UserManager.getUserByName(name); + userIds.add(user.getUserId()); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("No user by name [%s] [%s]", name, ex.getLocalizedMessage())); + } + } else if (UserRef instanceof UserByUserId) { + UserByUserId byUserId = (UserByUserId) UserRef; + String userId = byUserId.getUserId(); + if (!Strings.isValid(userId)) { + OseeLog.log(Activator.class, Level.WARNING, String.format("Unhandled UserByUserId id [%s]", userId)); + continue; + } + try { + User user = UserManager.getUserByUserId(userId); + userIds.add(user.getUserId()); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.WARNING, + String.format("No user by id [%s] [%s]", userId, ex.getLocalizedMessage())); + } + } else { + OseeLog.log(Activator.class, Level.WARNING, String.format("Unhandled UserRef type [%s]", UserRef)); + } + } + return userIds; + } + + private void setXWidgetNameBasedOnAttribute(AttributeType attributeType, WidgetDefinition widgetDef) throws OseeCoreException { + if (!Strings.isValid(widgetDef.getXWidgetName())) { + widgetDef.setXWidgetName(AttributeTypeToXWidgetName.getXWidgetName(attributeType)); + } + } + + private List<WidgetDefinition> retrieveWigetDefs(AtsDsl atsDsl, String SHEET_NAME) { + List<WidgetDefinition> widgetDefs = new ArrayList<WidgetDefinition>(); + for (WidgetDef dslWidgetDef : atsDsl.getWorkDef().getWidgetDefs()) { + WidgetDefinition widgetDef = convertDslWidgetDef(dslWidgetDef, SHEET_NAME); + widgetDefs.add(widgetDef); + } + return widgetDefs; + } + + private WidgetDefinition convertDslWidgetDef(WidgetDef dslWidgetDef, String SHEET_NAME) { + WidgetDefinition widgetDef = new WidgetDefinition(Strings.unquote(dslWidgetDef.getName())); + widgetDef.setAttributeName(dslWidgetDef.getAttributeName()); + // Set description if model defines it + if (Strings.isValid(dslWidgetDef.getDescription())) { + widgetDef.setDescription(dslWidgetDef.getDescription()); + } + // Else, set if AtsAttributeTypes defines it + else if (Strings.isValid(dslWidgetDef.getAttributeName()) && AtsAttributeTypes.getTypeByName(dslWidgetDef.getAttributeName()) != null && Strings.isValid(AtsAttributeTypes.getTypeByName( + dslWidgetDef.getAttributeName()).getDescription())) { + widgetDef.setDescription(AtsAttributeTypes.getTypeByName(dslWidgetDef.getAttributeName()).getDescription()); + } + if (Strings.isValid(dslWidgetDef.getXWidgetName())) { + widgetDef.setXWidgetName(dslWidgetDef.getXWidgetName()); + } else { + String attributeName = dslWidgetDef.getAttributeName(); + if (Strings.isValid(attributeName)) { + try { + AttributeType attributeType = AttributeTypeManager.getType(attributeName); + if (attributeType == null) { + OseeLog.log(Activator.class, Level.SEVERE, + String.format("Invalid attribute name [%s] in WorkDefinition [%s]", attributeName, SHEET_NAME)); + } else { + setXWidgetNameBasedOnAttribute(attributeType, widgetDef); + } + } catch (OseeCoreException ex) { + OseeLog.log( + Activator.class, + Level.SEVERE, + String.format("Error resolving attribute name [%s] in WorkDefinition [%s]", attributeName, SHEET_NAME)); + } + } else { + OseeLog.log(Activator.class, Level.SEVERE, + String.format("Invalid attribute name [%s] in WorkDefinition [%s]", attributeName, SHEET_NAME)); + } + } + + widgetDef.setHeight(dslWidgetDef.getHeight()); + widgetDef.setDefaultValue(dslWidgetDef.getDefaultValue()); + extractDslWidgetDefOptions(dslWidgetDef.getOption(), SHEET_NAME, widgetDef); + return widgetDef; + } + + private void extractDslWidgetDefOptions(EList<String> options, String SHEET_NAME, WidgetDefinition widgetDef) { + for (String value : options) { + WidgetOption option = null; + try { + option = WidgetOption.valueOf(value); + widgetDef.getOptions().add(option); + } catch (IllegalArgumentException ex) { + OseeLog.log(Activator.class, Level.WARNING, ex, "Unexpected value [%s] in WorkDefinition [%s] ", value, + SHEET_NAME); + } + } + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewDefinition.java new file mode 100644 index 00000000000..ac0fc0c967a --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewDefinition.java @@ -0,0 +1,96 @@ +/* + * Created on Jan 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.List; + +public class DecisionReviewDefinition { + + public String name; + public String reviewTitle; + public String description = ""; + public String relatedToState; + public ReviewBlockType blockingType; + public StateEventType stateEventType; + public List<String> assignees = new ArrayList<String>(); + public boolean autoTransitionToDecision = false; + public List<DecisionReviewOption> options = new ArrayList<DecisionReviewOption>(); + + public DecisionReviewDefinition(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ReviewBlockType getBlockingType() { + return blockingType; + } + + public void setBlockingType(ReviewBlockType blockingType) { + this.blockingType = blockingType; + } + + public StateEventType getStateEventType() { + return stateEventType; + } + + public void setStateEventType(StateEventType stateEventType) { + this.stateEventType = stateEventType; + } + + public boolean isAutoTransitionToDecision() { + return autoTransitionToDecision; + } + + public void setAutoTransitionToDecision(boolean autoTransitionToDecision) { + this.autoTransitionToDecision = autoTransitionToDecision; + } + + public List<String> getAssignees() { + return assignees; + } + + public List<DecisionReviewOption> getOptions() { + return options; + } + + @Override + public String toString() { + return name; + } + + public String getTitle() { + return reviewTitle; + } + + public void setReviewTitle(String reviewTitle) { + this.reviewTitle = reviewTitle; + } + + public String getRelatedToState() { + return relatedToState; + } + + public void setRelatedToState(String relatedToState) { + this.relatedToState = relatedToState; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewOption.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewOption.java new file mode 100644 index 00000000000..9a9e51eeb00 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/DecisionReviewOption.java @@ -0,0 +1,69 @@ +/* + * Created on Jan 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.List; + +public class DecisionReviewOption { + + public String name; + public boolean followupRequired; + public List<String> userIds; + public List<String> userNames; + + public DecisionReviewOption(String name) { + this(name, false, new ArrayList<String>()); + } + + public DecisionReviewOption(String name, boolean isFollowupRequired, List<String> userIds) { + this.name = name; + this.followupRequired = isFollowupRequired; + if (userIds == null) { + this.userIds = new ArrayList<String>(); + } else { + this.userIds = userIds; + } + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List<String> getUserIds() { + return userIds; + } + + public void setUserIds(List<String> userIds) { + this.userIds = userIds; + } + + public boolean isFollowupRequired() { + return followupRequired; + } + + public void setFollowupRequired(boolean followupRequired) { + this.followupRequired = followupRequired; + } + + @Override + public String toString() { + return name + (followupRequired ? " - Followup Required" : " - No Followup Required"); + } + + public List<String> getUserNames() { + return userNames; + } + + public void setUserNames(List<String> userNames) { + this.userNames = userNames; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/IWorkDefintionFactoryLegacyMgr.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/IWorkDefintionFactoryLegacyMgr.java new file mode 100644 index 00000000000..5e53d400874 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/IWorkDefintionFactoryLegacyMgr.java @@ -0,0 +1,27 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public interface IWorkDefintionFactoryLegacyMgr { + + public WorkDefinitionMatch getWorkFlowDefinitionFromId(String id) throws OseeCoreException; + + public WorkDefinitionMatch getWorkFlowDefinitionFromReverseId(String id) throws OseeCoreException; + + public WorkDefinitionMatch getWorkFlowDefinitionFromArtifact(Artifact artifact) throws OseeCoreException; + + public WorkDefinitionMatch getWorkFlowDefinitionFromTeamDefition(TeamDefinitionArtifact teamDefinition) throws OseeCoreException; + + public String getOverrideId(String legacyId); + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ModelUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ModelUtil.java new file mode 100644 index 00000000000..8d8170e0a6c --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ModelUtil.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workdef; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.Resource.Diagnostic; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; +import org.eclipse.osee.ats.dsl.AtsDslStandaloneSetup; +import org.eclipse.osee.ats.dsl.atsDsl.AtsDsl; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeExceptions; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.xtext.resource.SaveOptions; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.resource.XtextResourceSet; +import com.google.inject.Injector; + +/** + * @author Donald G. Dunne + */ +public final class ModelUtil { + + private ModelUtil() { + // Utility Class + } + + public static AtsDsl loadModel(InputStream inputStream, boolean isZipped) throws OseeCoreException { + Injector injector = new AtsDslStandaloneSetup().createInjectorAndDoEMFRegistration(); + XtextResource resource = injector.getInstance(XtextResource.class); + + Map<String, Boolean> options = new HashMap<String, Boolean>(); + options.put(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); + if (isZipped) { + options.put(Resource.OPTION_ZIP, Boolean.TRUE); + } + try { + resource.setURI(URI.createURI("http://www.eclipse.org/osee/ats/dsl/AtsDsl")); + resource.load(inputStream, options); + } catch (IOException ex) { + OseeExceptions.wrapAndThrow(ex); + } + AtsDsl model = (AtsDsl) resource.getContents().get(0); + for (Diagnostic diagnostic : resource.getErrors()) { + throw new OseeStateException(diagnostic.toString()); + } + return model; + } + + public static AtsDsl loadModel(String uri, String xTextData) throws OseeCoreException { + try { + AtsDslStandaloneSetup setup = new AtsDslStandaloneSetup(); + Injector injector = setup.createInjectorAndDoEMFRegistration(); + XtextResourceSet set = injector.getInstance(XtextResourceSet.class); + + // set.setClasspathURIContext(ModelUtil.class); + set.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); + + Resource resource = set.createResource(URI.createURI(uri)); + resource.load(new ByteArrayInputStream(xTextData.getBytes("UTF-8")), set.getLoadOptions()); + AtsDsl model = (AtsDsl) resource.getContents().get(0); + for (Diagnostic diagnostic : resource.getErrors()) { + throw new OseeStateException(diagnostic.toString()); + } + return model; + } catch (IOException ex) { + OseeExceptions.wrapAndThrow(ex); + return null; // unreachable since wrapAndThrow() always throws an exception + } + } + + public static void saveModel(AtsDsl model, String uri, OutputStream outputStream, boolean isZipped) throws IOException { + AtsDslStandaloneSetup.doSetup(); + + ResourceSet resourceSet = new ResourceSetImpl(); + Resource resource = resourceSet.createResource(URI.createURI(uri)); + resource.getContents().add(model); + + Map<String, Boolean> options = new HashMap<String, Boolean>(); + // options.put(XtextResource.OPTION_FORMAT, Boolean.TRUE); + if (isZipped) { + options.put(Resource.OPTION_ZIP, Boolean.TRUE); + } + SaveOptions saveOptions = SaveOptions.getOptions(options); + resource.save(outputStream, saveOptions.toOptionsMap()); + } + + private static void storeModel(Resource resource, OutputStream outputStream, EObject object, String uri, Map<String, Boolean> options) throws OseeCoreException { + try { + resource.setURI(URI.createURI(uri)); + resource.getContents().add(object); + resource.save(outputStream, options); + } catch (IOException ex) { + OseeExceptions.wrapAndThrow(ex); + } + } + + public static String modelToStringXML(EObject object, String uri, Map<String, Boolean> options) throws OseeCoreException { + return modelToString(new XMLResourceImpl(), object, uri, options); + } + + public static String modelToStringXText(EObject object, String uri, Map<String, Boolean> options) throws OseeCoreException { + AtsDslStandaloneSetup setup = new AtsDslStandaloneSetup(); + Injector injector = setup.createInjectorAndDoEMFRegistration(); + Resource resource = injector.getInstance(XtextResource.class); + Map<String, Boolean> options2 = new HashMap<String, Boolean>(); + options2.put(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); + return modelToString(resource, object, uri, options2); + } + + private static String modelToString(Resource resource, EObject object, String uri, Map<String, Boolean> options) throws OseeCoreException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + storeModel(resource, outputStream, object, uri, options); + try { + return outputStream.toString("UTF-8"); + } catch (UnsupportedEncodingException ex) { + OseeExceptions.wrapAndThrow(ex); + return null; // unreachable since wrapAndThrow() always throws an exception + } + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/PeerReviewDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/PeerReviewDefinition.java new file mode 100644 index 00000000000..058b6bf0e14 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/PeerReviewDefinition.java @@ -0,0 +1,91 @@ +/* + * Created on Jan 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.List; + +public class PeerReviewDefinition { + + public String name; + public String reviewTitle; + public String description = ""; + public String location = ""; + public String relatedToState; + public ReviewBlockType blockingType; + public StateEventType stateEventType; + public List<String> assignees = new ArrayList<String>(); + + public PeerReviewDefinition(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ReviewBlockType getBlockingType() { + return blockingType; + } + + public void setBlockingType(ReviewBlockType blockingType) { + this.blockingType = blockingType; + } + + public StateEventType getStateEventType() { + return stateEventType; + } + + public void setStateEventType(StateEventType stateEventType) { + this.stateEventType = stateEventType; + } + + public List<String> getAssignees() { + return assignees; + } + + @Override + public String toString() { + return name; + } + + public String getTitle() { + return reviewTitle; + } + + public void setReviewTitle(String reviewTitle) { + this.reviewTitle = reviewTitle; + } + + public String getRelatedToState() { + return relatedToState; + } + + public void setRelatedToState(String relatedToState) { + this.relatedToState = relatedToState; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ReviewBlockType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ReviewBlockType.java new file mode 100644 index 00000000000..c4436e5f1e9 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/ReviewBlockType.java @@ -0,0 +1,7 @@ +package org.eclipse.osee.ats.core.workdef; + +public enum ReviewBlockType { + None, + Transition, + Commit +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinition.java new file mode 100644 index 00000000000..527577b5844 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinition.java @@ -0,0 +1,23 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +public class RuleDefinition extends AbstractWorkDefItem { + + public RuleDefinition(String id) { + super(id); + } + + public RuleDefinition(RuleDefinitionOption ruleOption) { + super(ruleOption.name()); + } + + @Override + public String toString() { + return String.format("[%s]", getName()); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinitionOption.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinitionOption.java new file mode 100644 index 00000000000..0a56cc8534c --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleDefinitionOption.java @@ -0,0 +1,31 @@ +/* + * Created on Jan 26, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +public enum RuleDefinitionOption { + + RequireStateHourSpentPrompt("Work Page Option: Will popup a dialog to prompt user for time spent in this state."), + AddDecisionValidateBlockingReview("Work Page Option: Will auto-create a blocking decision review for this state requesting validation for this workflow."), + AddDecisionValidateNonBlockingReview("Work Page Option: Will auto-create a non blocking decision review requesting validation of workflow changes."), + AllowTransitionWithWorkingBranch("Work Page Option: Will allow transition to next state without committing current working branch."), + ForceAssigneesToTeamLeads("Work Page Option: Will force this state to be assigned back to the configured team leads. Useful for authorization state."), + RequireTargetedVersion("Work Page and Team Definition Option: Requires workflow to be targeted for version before transition is allowed."), + AllowPriviledgedEditToTeamMember("Work Page and Team Definition Option: Allow team member to priviledged edit workflow assigned to team."), + AllowPriviledgedEditToTeamMemberAndOriginator("Work Page and Team Definition Option: Allow team member to priviledged edit workflow assigned to team if user is originator."), + AllowPriviledgedEditToAll("Work Page and Team Definition Option: Allow anyone to priviledged edit workflow assigned to team."), + AllowEditToAll("Work Page and Team Definition Option: Allow anyone to edit workflow without being assignee."), + AllowAssigneeToAll("Work Page and Team Definition Option: Allow anyone to change workflow assignee without being assignee."); + + public final String description; + + public String getDescription() { + return description; + } + + private RuleDefinitionOption(String description) { + this.description = description; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleManager.java new file mode 100644 index 00000000000..2527f960f38 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/RuleManager.java @@ -0,0 +1,32 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.logging.OseeLog; + +/** + * @author Donald G. Dunne + */ +public class RuleManager { + + static Map<String, RuleDefinition> ruleMap = new HashMap<String, RuleDefinition>(30); + + public static RuleDefinition getOrCreateRule(String ruleId) { + if (!ruleMap.containsKey(ruleId)) { + try { + RuleDefinitionOption ruleOption = RuleDefinitionOption.valueOf(ruleId); + ruleMap.put(ruleId, new RuleDefinition(ruleOption)); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, null, "Unrecognized rule definition [%s]", ruleId); + } + } + return ruleMap.get(ruleId); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateColor.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateColor.java new file mode 100644 index 00000000000..77d9db99d75 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateColor.java @@ -0,0 +1,29 @@ +/* + * Created on May 4, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +/** + * @author Donald G. Dunne + */ +public enum StateColor { + BLACK, + WHITE, + RED, + DARK_RED, + GREEN, + DARK_GREEN, + YELLOW, + DARK_YELLOW, + BLUE, + DARK_BLUE, + MAGENTA, + DARK_MAGENTA, + CYAN, + DARK_CYAN, + GRAY, + DARK_GRAY; + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateDefinition.java new file mode 100644 index 00000000000..82aaa3bcd7b --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateDefinition.java @@ -0,0 +1,249 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.jdk.core.type.HashCollection; + +public class StateDefinition extends AbstractWorkDefItem implements IWorkPage { + + private WorkPageType workPageType; + private int ordinal = 0; + private final List<StateItem> stateItems = new ArrayList<StateItem>(5); + private final List<RuleDefinition> rules = new ArrayList<RuleDefinition>(5); + private final HashCollection<RuleDefinition, String> ruleToLocations = new HashCollection<RuleDefinition, String>(); + private final List<StateDefinition> toStates = new ArrayList<StateDefinition>(5); + private StateDefinition defaultToState; + private final List<StateDefinition> overrideAttributeValidationStates = new ArrayList<StateDefinition>(5); + private final List<DecisionReviewDefinition> decisionReviews = new ArrayList<DecisionReviewDefinition>(); + private final List<PeerReviewDefinition> peerReviews = new ArrayList<PeerReviewDefinition>(); + private WorkDefinition workDefinition; + private int percentWeight = 0; + private int recommendedPercentComplete = 0; + private StateColor color = null; + + public StateDefinition(String name) { + super(name); + } + + public List<StateItem> getStateItems() { + return stateItems; + } + + public void addRule(RuleDefinition ruleDef, String location) { + rules.add(ruleDef); + ruleToLocations.put(ruleDef, location); + } + + public Collection<String> getRuleLocations(RuleDefinition ruleDef) { + return ruleToLocations.getValues(ruleDef); + } + + public List<RuleDefinition> getRules() { + return rules; + } + + @Override + public WorkPageType getWorkPageType() { + return workPageType; + } + + public void setWorkPageType(WorkPageType workPageType) { + this.workPageType = workPageType; + } + + public int getOrdinal() { + return ordinal; + } + + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + + @Override + public boolean isCompletedOrCancelledPage() { + return getWorkPageType().isCompletedOrCancelledPage(); + } + + @Override + public boolean isCompletedPage() { + return getWorkPageType().isCompletedPage(); + } + + @Override + public boolean isCancelledPage() { + return getWorkPageType().isCancelledPage(); + } + + @Override + public boolean isWorkingPage() { + return getWorkPageType().isWorkingPage(); + } + + public List<StateDefinition> getToStates() { + return toStates; + } + + @Override + public String getPageName() { + return getName(); + } + + @Override + public Integer getDefaultPercent() { + return null; + } + + public WorkDefinition getWorkDefinition() { + return workDefinition; + } + + public void setWorkDefinition(WorkDefinition workDefinition) { + this.workDefinition = workDefinition; + } + + public boolean hasRule(RuleDefinitionOption option) { + return hasRule(option.name()); + } + + public boolean hasRule(String name) { + for (RuleDefinition rule : rules) { + if (rule.getName().equals(name)) { + return true; + } + } + return false; + } + + public List<RuleDefinition> getRulesStartsWith(String name) { + List<RuleDefinition> results = new ArrayList<RuleDefinition>(); + for (RuleDefinition rule : rules) { + if (rule.getName().startsWith(name)) { + results.add(rule); + } + } + return results; + } + + @Override + public String toString() { + return String.format("[%s][%s]", getName(), getWorkPageType()); + } + + /** + * Returns fully qualified name of <work definition name>.<this state name + */ + public String getFullName() { + if (workDefinition != null) { + return workDefinition.getName() + "." + getName(); + } + return getName(); + } + + public List<StateDefinition> getOverrideAttributeValidationStates() { + return overrideAttributeValidationStates; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getFullName() == null) ? 0 : getFullName().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + StateDefinition other = (StateDefinition) obj; + if (getFullName() == null) { + if (other.getFullName() != null) { + return false; + } + } else if (!getFullName().equals(other.getFullName())) { + return false; + } + return true; + } + + /** + * Recursively decend StateItems and grab all widgetDefs + */ + public List<WidgetDefinition> getWidgets() { + List<WidgetDefinition> widgets = new ArrayList<WidgetDefinition>(); + getWidgets(widgets, getStateItems()); + return widgets; + } + + private void getWidgets(List<WidgetDefinition> widgets, List<StateItem> stateItems) { + for (StateItem stateItem : stateItems) { + if (stateItem instanceof CompositeStateItem) { + getWidgets(widgets, ((CompositeStateItem) stateItem).getStateItems()); + } else if (stateItem instanceof WidgetDefinition) { + widgets.add((WidgetDefinition) stateItem); + } + } + } + + public StateDefinition getDefaultToState() { + return defaultToState; + } + + public void setDefaultToState(StateDefinition defaultToState) { + this.defaultToState = defaultToState; + } + + public List<DecisionReviewDefinition> getDecisionReviews() { + return decisionReviews; + } + + public List<PeerReviewDefinition> getPeerReviews() { + return peerReviews; + } + + public int getStateWeight() { + return percentWeight; + } + + /** + * Set how much (of 100%) this state's percent complete will contribute to the full percent complete of work + * definitions. + * + * @param percentWeight int value where all stateWeights in workdefinition == 100 + */ + public void setPercentWeight(int percentWeight) { + this.percentWeight = percentWeight; + } + + public void setRecommendedPercentComplete(int recommendedPercentComplete) { + this.recommendedPercentComplete = recommendedPercentComplete; + } + + public int getRecommendedPercentComplete() { + return recommendedPercentComplete; + } + + public void setColor(StateColor stateColor) { + this.color = stateColor; + } + + public StateColor getColor() { + return color; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateEventType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateEventType.java new file mode 100644 index 00000000000..07c2a64e882 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateEventType.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workdef; + +/** + * @author Donald G. Dunne + */ +public enum StateEventType { + None, + TransitionTo, + CreateBranch, + CommitBranch; +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateItem.java new file mode 100644 index 00000000000..086bc3571dd --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/StateItem.java @@ -0,0 +1,14 @@ +/* + * Created on Dec 16, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +public class StateItem extends AbstractWorkDefItem { + + public StateItem(String name) { + super(name); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetDefinition.java new file mode 100644 index 00000000000..9e01e5dcd82 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetDefinition.java @@ -0,0 +1,89 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +public class WidgetDefinition extends StateItem { + + private String attributeName; + private String toolTip; + private String description; + private int height; + private String xWidgetName; + private String defaultValue; + private final WidgetOptionHandler options = new WidgetOptionHandler(); + + public WidgetDefinition(String name) { + super(name); + } + + public String getAtrributeName() { + return attributeName; + } + + public void setAttributeName(String storeName) { + this.attributeName = storeName; + } + + public String getToolTip() { + return toolTip; + } + + public void setToolTip(String toolTip) { + this.toolTip = toolTip; + } + + public boolean is(WidgetOption widgetOption) { + return options.contains(widgetOption); + } + + public void set(WidgetOption widgetOption) { + options.add(widgetOption); + } + + public String getXWidgetName() { + return xWidgetName; + } + + public void setXWidgetName(String xWidgetName) { + this.xWidgetName = xWidgetName; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public void setDescription(String description) { + this.description = description; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + @Override + public String toString() { + return String.format("[%s][%s]", getName(), getAtrributeName()); + } + + public WidgetOptionHandler getOptions() { + return options; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOption.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOption.java new file mode 100644 index 00000000000..cbaec87cb9f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOption.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workdef; + +/** + * @author Donald G. Dunne + */ +public enum WidgetOption { + NONE, + + REQUIRED_FOR_TRANSITION, + NOT_REQUIRED_FOR_TRANSITION, + + REQUIRED_FOR_COMPLETION, + NOT_REQUIRED_FOR_COMPLETION, + + ENABLED, + NOT_ENABLED, + + EDITABLE, + NOT_EDITABLE, + + MULTI_SELECT, + + HORIZONTAL_LABEL, + VERTICAL_LABEL, + + LABEL_AFTER, + LABEL_BEFORE, + + NO_LABEL, + + SORTED, + + ADD_DEFAULT_VALUE, + NO_DEFAULT_VALUE, + + BEGIN_COMPOSITE_4, + BEGIN_COMPOSITE_6, + BEGIN_COMPOSITE_8, + BEGIN_COMPOSITE_10, + END_COMPOSITE, + + // Fill Options + FILL_NONE, + FILL_HORIZONTALLY, + FILL_VERTICALLY, + + // Align Options + ALIGN_LEFT, + ALIGN_RIGHT, + ALIGN_CENTER; + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOptionHandler.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOptionHandler.java new file mode 100644 index 00000000000..4f0bb9660f0 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WidgetOptionHandler.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workdef; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Donald G. Dunne + */ +public class WidgetOptionHandler { + + private final Set<WidgetOption> options = new HashSet<WidgetOption>(); + + public WidgetOptionHandler(WidgetOption... xOption) { + set(xOption); + } + + public static Collection<WidgetOption> getCollection(WidgetOption... ats) { + Set<WidgetOption> items = new HashSet<WidgetOption>(); + for (WidgetOption item : ats) { + items.add(item); + } + return items; + } + + public void add(WidgetOption xOption) { + if (xOption.name().startsWith("ALIGN_")) { + options.remove(WidgetOption.ALIGN_CENTER); + options.remove(WidgetOption.ALIGN_LEFT); + options.remove(WidgetOption.ALIGN_RIGHT); + } else if (xOption == WidgetOption.HORIZONTAL_LABEL) { + options.remove(WidgetOption.VERTICAL_LABEL); + } else if (xOption == WidgetOption.EDITABLE) { + options.remove(WidgetOption.NOT_EDITABLE); + } else if (xOption == WidgetOption.NOT_EDITABLE) { + options.remove(WidgetOption.EDITABLE); + } else if (xOption == WidgetOption.NOT_REQUIRED_FOR_COMPLETION) { + options.remove(WidgetOption.REQUIRED_FOR_COMPLETION); + } else if (xOption == WidgetOption.REQUIRED_FOR_COMPLETION) { + options.remove(WidgetOption.NOT_REQUIRED_FOR_COMPLETION); + } else if (xOption == WidgetOption.NOT_REQUIRED_FOR_TRANSITION) { + options.remove(WidgetOption.REQUIRED_FOR_TRANSITION); + } else if (xOption == WidgetOption.REQUIRED_FOR_TRANSITION) { + options.remove(WidgetOption.NOT_REQUIRED_FOR_TRANSITION); + } else if (xOption == WidgetOption.NOT_ENABLED) { + options.remove(WidgetOption.ENABLED); + } else if (xOption == WidgetOption.ENABLED) { + options.remove(WidgetOption.NOT_ENABLED); + } else if (xOption == WidgetOption.FILL_NONE) { + options.remove(WidgetOption.FILL_HORIZONTALLY); + options.remove(WidgetOption.FILL_VERTICALLY); + } else if (xOption == WidgetOption.VERTICAL_LABEL) { + options.remove(WidgetOption.HORIZONTAL_LABEL); + } + options.add(xOption); + } + + public void add(WidgetOption... xOption) { + for (WidgetOption xOpt : xOption) { + add(xOpt); + } + } + + public void add(Collection<WidgetOption> xOption) { + for (WidgetOption xOpt : xOption) { + add(xOpt); + } + } + + public boolean contains(WidgetOption xOption) { + return options.contains(xOption); + } + + public Set<WidgetOption> getXOptions() { + return options; + } + + public void set(Set<WidgetOption> options) { + this.options.clear(); + // Must go through the add method to ensure values set properly + for (WidgetOption xOption : options) { + add(xOption); + } + } + + public void set(WidgetOption options[]) { + this.options.clear(); + // Must go through the add method to ensure values set properly + for (WidgetOption xOption : options) { + add(xOption); + } + } + + @Override + public String toString() { + return String.valueOf(options); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinition.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinition.java new file mode 100644 index 00000000000..769dd52c5e5 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinition.java @@ -0,0 +1,205 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osee.ats.core.internal.Activator; + +public class WorkDefinition extends AbstractWorkDefItem { + + private final List<StateDefinition> states = new ArrayList<StateDefinition>(5); + private final List<RuleDefinition> rules = new ArrayList<RuleDefinition>(5); + private final Set<String> ids = new HashSet<String>(); + private StateDefinition startState; + private String version; + + public WorkDefinition(String name) { + super(name); + ids.add(name); + } + + public List<StateDefinition> getStates() { + return states; + } + + public List<StateDefinition> getStatesOrdered() { + if (startState == null) { + throw new IllegalArgumentException("Can't locate Start State for workflow " + getName()); + } + + // Get ordered pages starting with start page + List<StateDefinition> orderedPages = new ArrayList<StateDefinition>(); + getOrderedStates(startState, orderedPages); + + // Move completed to the end if it exists + StateDefinition completedPage = null; + for (StateDefinition stateDefinition : orderedPages) { + if (stateDefinition.isCompletedPage()) { + completedPage = stateDefinition; + } + } + if (completedPage != null) { + orderedPages.remove(completedPage); + orderedPages.add(completedPage); + } + // for (WorkPage wPage : orderedPages) + // System.out.println("Ordered Page: - " + wPage); + return orderedPages; + } + + private void getOrderedStates(StateDefinition stateDefinition, List<StateDefinition> pages) { + if (pages.contains(stateDefinition)) { + return; + } + // Add this page first + pages.add(stateDefinition); + // Add default page + StateDefinition defaultToState = getDefaultToState(stateDefinition); + if (defaultToState != null && !defaultToState.getName().equals(stateDefinition.getName())) { + getOrderedStates(getDefaultToState(stateDefinition), pages); + } + // Add remaining pages + for (StateDefinition stateDef : stateDefinition.getToStates()) { + if (!pages.contains(stateDef)) { + getOrderedStates(stateDef, pages); + } + } + } + + public StateDefinition getDefaultToState(StateDefinition stateDefinition) { + return stateDefinition.getDefaultToState(); + } + + public Collection<String> getStateNames() { + List<String> names = new ArrayList<String>(); + for (StateDefinition state : states) { + names.add(state.getName()); + } + return names; + } + + public StateDefinition getStateByName(String name) { + for (StateDefinition state : states) { + if (state.getName().equals(name)) { + return state; + } + } + return null; + } + + public boolean hasRule(String name) { + for (RuleDefinition rule : rules) { + if (rule.getName().equals(name)) { + return true; + } + } + return false; + } + + public List<RuleDefinition> getRulesStartsWith(String name) { + List<RuleDefinition> results = new ArrayList<RuleDefinition>(); + for (RuleDefinition rule : rules) { + if (rule.getName().startsWith(name)) { + results.add(rule); + } + } + return results; + } + + public List<RuleDefinition> getRules() { + return rules; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AbstractWorkDefItem other = (AbstractWorkDefItem) obj; + if (getName() == null) { + if (other.getName() != null) { + return false; + } + } else if (!getName().equals(other.getName())) { + return false; + } + return true; + } + + public StateDefinition getOrCreateState(String name) { + StateDefinition stateDef = getStateByName(name); + if (stateDef == null) { + stateDef = new StateDefinition(name); + getStates().add(stateDef); + } + return stateDef; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public StateDefinition getStartState() { + return startState; + } + + public void setStartState(StateDefinition startState) { + this.startState = startState; + } + + public Set<String> getIds() { + return ids; + } + + public boolean isStateWeightingEnabled() { + for (StateDefinition stateDef : getStates()) { + if (stateDef.getStateWeight() != 0) { + return true; + } + } + return false; + } + + public IStatus validateStateWeighting() { + if (!isStateWeightingEnabled()) { + return Status.OK_STATUS; + } + int total = 0; + for (StateDefinition stateDef : getStates()) { + total += stateDef.getStateWeight(); + } + if (total != 100) { + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, String.format( + "Total weight only %d, needs to equal 100 for all states", total)); + } + return Status.OK_STATUS; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactory.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactory.java new file mode 100644 index 00000000000..473d1382ae3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactory.java @@ -0,0 +1,256 @@ +/* + * Created on Dec 15, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkflowProviders; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.util.WorkflowManagerCore; +import org.eclipse.osee.ats.core.workdef.provider.AtsWorkDefinitionProviderCore; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.ITeamWorkflowProvider; +import org.eclipse.osee.framework.core.enums.DeletionFlag; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; + +public class WorkDefinitionFactory { + + // Cache the WorkDefinition used for each AbstractWorkflowId so don't have to recompute each time + private static final Map<String, WorkDefinitionMatch> awaHridToWorkDefinitions = + new HashMap<String, WorkDefinitionMatch>(); + // Cache the WorkDefinition object for each WorkDefinition id so don't have to reload + // This grows as WorkDefinitions are requested/loaded + private static final Map<String, WorkDefinitionMatch> workDefIdToWorkDefintion = + new HashMap<String, WorkDefinitionMatch>(); + public static final String TaskWorkflowDefinitionId = "osee.ats.taskWorkflow"; + public static final String GoalWorkflowDefinitionId = "osee.ats.goalWorkflow"; + public static final String PeerToPeerWorkflowDefinitionId = "osee.ats.peerToPeerReview"; + public static final String DecisionWorkflowDefinitionId = "osee.ats.decisionReview"; + + public static void clearCaches() { + awaHridToWorkDefinitions.clear(); + workDefIdToWorkDefintion.clear(); + } + + public static WorkDefinitionMatch getWorkDefinition(Artifact artifact) throws OseeCoreException { + if (!awaHridToWorkDefinitions.containsKey(artifact.getHumanReadableId())) { + WorkDefinitionMatch match = getWorkDefinitionNew(artifact); + if (!match.isMatched()) { + match = WorkDefinitionFactoryLegacyMgr.getWorkFlowDefinitionFromArtifact(artifact); + } + awaHridToWorkDefinitions.put(artifact.getHumanReadableId(), match); + } + return awaHridToWorkDefinitions.get(artifact.getHumanReadableId()); + } + + public static WorkDefinitionMatch getWorkDefinition(String id) throws OseeCoreException { + if (!workDefIdToWorkDefintion.containsKey(id)) { + WorkDefinitionMatch match = new WorkDefinitionMatch(); + String translatedId = WorkDefinitionFactory.getOverrideWorkDefId(id); + // Try to get from new DSL provider if configured to use it + if (!match.isMatched()) { + WorkDefinition workDef = AtsWorkDefinitionProviderCore.get().getWorkFlowDefinition(translatedId); + if (workDef != null) { + match.setWorkDefinition(workDef); + match.addTrace((String.format("from DSL provider loaded id [%s] and override translated Id [%s]", id, + translatedId))); + } + } + // Otherwise, just translate legacy WorkFlowDefinition from artifact + if (!match.isMatched()) { + match = WorkDefinitionFactoryLegacyMgr.getWorkFlowDefinitionFromId(id); + } + // If still no match, configuration may have new workdef id but not set to use them + // Attempt to get back to original id and load through WorkFlowDefinition translate + if (!match.isMatched()) { + match = WorkDefinitionFactoryLegacyMgr.getWorkFlowDefinitionFromReverseId(id); + } + if (match.isMatched()) { + System.out.println("Loaded " + match); + workDefIdToWorkDefintion.put(id, match); + } + } + WorkDefinitionMatch match = workDefIdToWorkDefintion.get(id); + if (match == null) { + match = new WorkDefinitionMatch(); + } + return match; + } + + private static WorkDefinitionMatch getWorkDefinitionFromArtifactsAttributeValue(Artifact artifact) throws OseeCoreException { + // If this artifact specifies it's own workflow definition, use it + String workFlowDefId = artifact.getSoleAttributeValue(AtsAttributeTypes.WorkflowDefinition, null); + if (Strings.isValid(workFlowDefId)) { + String translatedId = WorkDefinitionFactory.getOverrideWorkDefId(workFlowDefId); + WorkDefinitionMatch match = getWorkDefinition(translatedId); + if (match.isMatched()) { + match.addTrace(String.format("from artifact [%s] for id [%s] and override translated Id [%s]", artifact, + workFlowDefId, translatedId)); + return match; + } + } + return new WorkDefinitionMatch(); + } + + private static WorkDefinitionMatch getTaskWorkDefinitionFromArtifactsAttributeValue(Artifact artifact) throws OseeCoreException { + // If this artifact specifies it's own workflow definition, use it + String workFlowDefId = artifact.getSoleAttributeValue(AtsAttributeTypes.RelatedTaskWorkDefinition, null); + if (Strings.isValid(workFlowDefId)) { + String translatedId = WorkDefinitionFactory.getOverrideWorkDefId(workFlowDefId); + WorkDefinitionMatch match = getWorkDefinition(translatedId); + if (match.isMatched()) { + match.addTrace(String.format("from artifact [%s] for id [%s] and override translated Id [%s]", artifact, + workFlowDefId, translatedId)); + return match; + } + } + return new WorkDefinitionMatch(); + } + + /** + * Look at team def's attribute for Work Definition setting, otherwise, walk up team tree for setting + */ + private static WorkDefinitionMatch getWorkDefinitionFromTeamDefinitionAttributeInherited(TeamDefinitionArtifact teamDef) throws OseeCoreException { + WorkDefinitionMatch match = getWorkDefinitionFromArtifactsAttributeValue(teamDef); + if (match.isMatched()) { + return match; + } + Artifact parentArt = teamDef.getParent(); + if (parentArt != null && parentArt instanceof TeamDefinitionArtifact) { + return getWorkDefinitionFromTeamDefinitionAttributeInherited((TeamDefinitionArtifact) parentArt); + } + return new WorkDefinitionMatch(); + } + + private static WorkDefinitionMatch getWorkDefinitionForTask(Artifact taskArt) throws OseeCoreException { + WorkDefinitionMatch match = new WorkDefinitionMatch(); + AbstractWorkflowArtifact parentAwa = WorkflowManagerCore.getParentAWA(taskArt); + for (ITeamWorkflowProvider provider : TeamWorkflowProviders.getAtsTeamWorkflowExtensions()) { + String workFlowDefId = provider.getRelatedTaskWorkflowDefinitionId(parentAwa); + if (Strings.isValid(workFlowDefId)) { + String translatedId = getOverrideWorkDefId(workFlowDefId); + match = WorkDefinitionFactory.getWorkDefinition(translatedId); + match.addTrace((String.format("from provider [%s] for id [%s] and override translated Id [%s]", + provider.getClass().getSimpleName(), workFlowDefId, translatedId))); + break; + } + } + if (!match.isMatched()) { + // If task specifies it's own workflow id, use it + match = getWorkDefinitionFromArtifactsAttributeValue(taskArt); + } + if (!match.isMatched()) { + // Else If parent SMA has a related task definition workflow id specified, use it + WorkDefinitionMatch match2 = getTaskWorkDefinitionFromArtifactsAttributeValue(parentAwa); + if (match2.isMatched()) { + match2.addTrace(String.format("from task parent SMA [%s]", parentAwa)); + match = match2; + } + } + if (!match.isMatched()) { + // Else If parent TeamWorkflow's TeamDefinition has a related task definition workflow id, use it + match = getTaskWorkDefinitionFromArtifactsAttributeValue(WorkflowManagerCore.getTeamDefinition(taskArt)); + } + if (!match.isMatched()) { + // Else, use default Task workflow + String translatedId = getOverrideWorkDefId(TaskWorkflowDefinitionId); + match = getWorkDefinition(translatedId); + if (match.isMatched()) { + match.addTrace(String.format("default TaskWorkflowDefinition ID [%s] and override translated Id [%s]", + TaskWorkflowDefinitionId, translatedId)); + } + } + return match; + } + + private static WorkDefinitionMatch getWorkDefinitionNew(Artifact artifact) throws OseeCoreException { + WorkDefinitionMatch match = new WorkDefinitionMatch(); + if (artifact.isOfType(AtsArtifactTypes.Task)) { + match = getWorkDefinitionForTask(artifact); + } + if (!match.isMatched() && artifact instanceof AbstractWorkflowArtifact) { + AbstractWorkflowArtifact aba = (AbstractWorkflowArtifact) artifact; + // Check extensions for definition handling + for (ITeamWorkflowProvider provider : TeamWorkflowProviders.getAtsTeamWorkflowExtensions()) { + String workFlowDefId = provider.getWorkflowDefinitionId(aba); + if (Strings.isValid(workFlowDefId)) { + match = + WorkDefinitionFactory.getWorkDefinition(WorkDefinitionFactory.getOverrideWorkDefId(workFlowDefId)); + } + } + if (!match.isMatched()) { + // If this artifact specifies it's own workflow definition, use it + match = getWorkDefinitionFromArtifactsAttributeValue(artifact); + if (!match.isMatched()) { + // Otherwise, use workflow defined by attribute of WorkflowDefinition + // Note: This is new. Old TeamDefs got workflow off relation + if (artifact.isOfType(AtsArtifactTypes.TeamWorkflow)) { + TeamDefinitionArtifact teamDef = ((TeamWorkFlowArtifact) artifact).getTeamDefinition(); + match = getWorkDefinitionFromTeamDefinitionAttributeInherited(teamDef); + if (!match.isMatched()) { + match = ((TeamWorkFlowArtifact) artifact).getTeamDefinition().getWorkDefinition(); + } + } else if (artifact.isOfType(AtsArtifactTypes.Goal)) { + match = getWorkDefinition(getOverrideWorkDefId(GoalWorkflowDefinitionId)); + match.addTrace(String.format("Override translated from id [%s]", GoalWorkflowDefinitionId)); + } else if (artifact.isOfType(AtsArtifactTypes.PeerToPeerReview)) { + match = getWorkDefinition(getOverrideWorkDefId(PeerToPeerWorkflowDefinitionId)); + match.addTrace(String.format("Override translated from id [%s]", PeerToPeerWorkflowDefinitionId)); + } else if (artifact.isOfType(AtsArtifactTypes.DecisionReview)) { + match = getWorkDefinition(getOverrideWorkDefId(DecisionWorkflowDefinitionId)); + match.addTrace(String.format("Override translated from id [%s]", DecisionWorkflowDefinitionId)); + } + } + } + } + return match; + } + + public static Set<String> errorDisplayed = new HashSet<String>(); + + public static String getOverrideWorkDefId(String id) { + // Don't override if no providers available (dsl plugins not released) + String overrideId = WorkDefinitionFactoryLegacyMgr.getOverrideId(id); + if (Strings.isValid(overrideId)) { + // Only display this override once in log + if (!errorDisplayed.contains(overrideId)) { + OseeLog.log(Activator.class, Level.INFO, + String.format("Override WorkDefinition [%s] with [%s]", id, overrideId)); + errorDisplayed.add(overrideId); + } + return overrideId; + } + return id; + } + + public static Set<WorkDefinition> loadAllDefinitions() throws OseeCoreException { + Set<WorkDefinition> workDefs = new HashSet<WorkDefinition>(); + // This load is faster than loading each by artifact type + for (Artifact art : ArtifactQuery.getArtifactListFromType(AtsArtifactTypes.WorkDefinition, + AtsUtilCore.getAtsBranch(), DeletionFlag.EXCLUDE_DELETED)) { + try { + WorkDefinition workDef = AtsWorkDefinitionProviderCore.get().loadWorkDefinitionFromArtifact(art); + workDefs.add(workDef); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, + "Error loading WorkDefinition from artifact " + art.toStringWithId(), ex); + } + } + return workDefs; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactoryLegacyMgr.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactoryLegacyMgr.java new file mode 100644 index 00000000000..1aacd542296 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionFactoryLegacyMgr.java @@ -0,0 +1,91 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.osgi.framework.Bundle; + +/** + * @author Donald G. Dunne + */ +public class WorkDefinitionFactoryLegacyMgr { + + public static WorkDefinitionMatch getWorkFlowDefinitionFromId(String id) throws OseeCoreException { + ensureLoaded(); + return legacyMgr.getWorkFlowDefinitionFromId(id); + } + + public static WorkDefinitionMatch getWorkFlowDefinitionFromReverseId(String id) throws OseeCoreException { + ensureLoaded(); + return legacyMgr.getWorkFlowDefinitionFromReverseId(id); + } + + public static WorkDefinitionMatch getWorkFlowDefinitionFromArtifact(Artifact artifact) throws OseeCoreException { + ensureLoaded(); + return legacyMgr.getWorkFlowDefinitionFromArtifact(artifact); + } + + public static WorkDefinitionMatch getWorkFlowDefinitionFromTeamDefinition(TeamDefinitionArtifact teamDefinition) throws OseeCoreException { + ensureLoaded(); + return legacyMgr.getWorkFlowDefinitionFromTeamDefition(teamDefinition); + } + + public static String getOverrideId(String legacyId) { + ensureLoaded(); + return legacyMgr.getOverrideId(legacyId); + } + + private static IWorkDefintionFactoryLegacyMgr legacyMgr; + + /* + * due to lazy initialization, this function is non-reentrant therefore, the synchronized keyword is necessary + */ + public synchronized static void ensureLoaded() { + if (legacyMgr == null) { + + IExtensionPoint point = + Platform.getExtensionRegistry().getExtensionPoint( + "org.eclipse.osee.ats.core.AtsLegacyWorkDefinitionProvider"); + if (point == null) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, + "Can't access AtsLegacyWorkDefinitionProvider extension point"); + } + IExtension[] extensions = point.getExtensions(); + for (IExtension extension : extensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + String classname = null; + String bundleName = null; + for (IConfigurationElement el : elements) { + if (el.getName().equals("AtsLegacyWorkDefinitionProvider")) { + classname = el.getAttribute("classname"); + bundleName = el.getContributor().getName(); + if (classname != null && bundleName != null) { + Bundle bundle = Platform.getBundle(bundleName); + try { + Class<?> taskClass = bundle.loadClass(classname); + Object obj = taskClass.newInstance(); + legacyMgr = (IWorkDefintionFactoryLegacyMgr) obj; + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, + "Error loading AtsLegacyWorkDefinitionProvider extension", ex); + } + } + } + } + } + } + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionMatch.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionMatch.java new file mode 100644 index 00000000000..9e1aaeeedd4 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionMatch.java @@ -0,0 +1,54 @@ +/* + * Created on Jan 10, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.osee.framework.jdk.core.util.Strings; + +public class WorkDefinitionMatch { + + private WorkDefinition workDefinition; + private final List<String> trace = new ArrayList<String>(); + + public WorkDefinitionMatch() { + this(null, null); + } + + public WorkDefinitionMatch(WorkDefinition WorkDefinition, String trace) { + this.workDefinition = WorkDefinition; + if (Strings.isValid(trace)) { + this.trace.add(trace); + } + } + + public WorkDefinition getWorkDefinition() { + return workDefinition; + } + + public void setWorkDefinition(WorkDefinition WorkDefinition) { + this.workDefinition = WorkDefinition; + } + + public void addTrace(String traceStr) { + if (trace.size() == 0 || (trace.size() >= 1 && !trace.get(trace.size() - 1).equals(traceStr))) { + trace.add(traceStr); + } + } + + public List<String> getTrace() { + return trace; + } + + public boolean isMatched() { + return workDefinition != null; + } + + @Override + public String toString() { + return workDefinition.getName(); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionSheet.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionSheet.java new file mode 100644 index 00000000000..cc953d065d6 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/WorkDefinitionSheet.java @@ -0,0 +1,39 @@ +/* + * Created on Jan 19, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef; + +import java.io.File; + +public class WorkDefinitionSheet { + + public File file; + public String name; + public String legacyOverrideId; + + public WorkDefinitionSheet(String name, String legacyOverrideId, File file) { + super(); + this.file = file; + this.name = name; + this.legacyOverrideId = legacyOverrideId; + } + + public File getFile() { + return file; + } + + public String getName() { + return name; + } + + public String getLegacyOverrideId() { + return legacyOverrideId; + } + + @Override + public String toString() { + return String.format("%s filename[%s] overrideId[%s]", name, file, legacyOverrideId); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/AtsWorkDefinitionProviderCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/AtsWorkDefinitionProviderCore.java new file mode 100644 index 00000000000..ab152d15ab9 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/AtsWorkDefinitionProviderCore.java @@ -0,0 +1,65 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef.provider; + +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workdef.ConvertAtsDslToWorkDefinition; +import org.eclipse.osee.ats.core.workdef.ModelUtil; +import org.eclipse.osee.ats.core.workdef.WorkDefinition; +import org.eclipse.osee.ats.dsl.atsDsl.AtsDsl; +import org.eclipse.osee.framework.core.exception.ArtifactDoesNotExist; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeWrappedException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.BranchManager; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; + +/** + * @author Donald G. Dunne + */ +public class AtsWorkDefinitionProviderCore { + + private static AtsWorkDefinitionProviderCore provider = new AtsWorkDefinitionProviderCore(); + + public static AtsWorkDefinitionProviderCore get() { + return provider; + } + + public WorkDefinition getWorkFlowDefinition(String id) throws OseeCoreException { + WorkDefinition workDef = loadWorkDefinitionFromArtifact(id); + return workDef; + } + + private WorkDefinition loadWorkDefinitionFromArtifact(String name) throws OseeCoreException { + Artifact artifact = null; + try { + artifact = + ArtifactQuery.getArtifactFromTypeAndName(AtsArtifactTypes.WorkDefinition, name, + BranchManager.getCommonBranch()); + return loadWorkDefinitionFromArtifact(artifact); + } catch (ArtifactDoesNotExist ex) { + // do nothing + } catch (Exception ex) { + throw new OseeWrappedException(String.format("Error loading AtsDsl [%s] from Artifact", name), ex); + } + return null; + } + + public WorkDefinition loadWorkDefinitionFromArtifact(Artifact artifact) throws OseeCoreException { + String modelText = artifact.getAttributesToString(AtsAttributeTypes.DslSheet); + String modelName = artifact.getName() + ".ats"; + AtsDsl atsDsl = loadAtsDsl(modelName, modelText); + ConvertAtsDslToWorkDefinition converter = new ConvertAtsDslToWorkDefinition(modelName, atsDsl); + return converter.convert(); + }; + + public static AtsDsl loadAtsDsl(String name, String modelText) throws OseeCoreException { + AtsDsl atsDsl = ModelUtil.loadModel(name, modelText); + return atsDsl; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/BooleanDefUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/BooleanDefUtil.java new file mode 100644 index 00000000000..03ba022805d --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/BooleanDefUtil.java @@ -0,0 +1,22 @@ +/* + * Created on Feb 2, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef.provider; + +import org.eclipse.osee.ats.dsl.atsDsl.BooleanDef; + +public class BooleanDefUtil { + + /** + * @return if BooleanDef == null return defaultValue, else true or false + */ + public static boolean get(BooleanDef booleanDef, boolean defaultValue) { + if (booleanDef != null && booleanDef != BooleanDef.NONE) { + return booleanDef == BooleanDef.TRUE; + } + return defaultValue; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/UserRefUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/UserRefUtil.java new file mode 100644 index 00000000000..5ba71ff57d2 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workdef/provider/UserRefUtil.java @@ -0,0 +1,56 @@ +/* + * Created on Feb 2, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workdef.provider; + +import java.util.HashSet; +import java.util.Set; +import org.eclipse.emf.common.util.EList; +import org.eclipse.osee.ats.dsl.atsDsl.UserByName; +import org.eclipse.osee.ats.dsl.atsDsl.UserByUserId; +import org.eclipse.osee.ats.dsl.atsDsl.UserRef; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +public class UserRefUtil { + + public static Set<String> getUserIds(EList<UserRef> userRefs) { + Set<String> userIds = new HashSet<String>(); + for (UserRef UserRef : userRefs) { + if (UserRef instanceof UserByUserId) { + userIds.add(((UserByUserId) UserRef).getUserId()); + } + } + return userIds; + } + + public static Set<String> getUserNames(EList<UserRef> userRefs) { + Set<String> userNames = new HashSet<String>(); + for (UserRef UserRef : userRefs) { + if (UserRef instanceof UserByName) { + userNames.add(Strings.unquote(((UserByName) UserRef).getUserName())); + } + } + return userNames; + } + + public static Set<Artifact> getUsers(EList<UserRef> userRefs) throws OseeCoreException { + Set<Artifact> users = new HashSet<Artifact>(); + if (userRefs != null) { + for (String userId : getUserIds(userRefs)) { + User user = UserManager.getUserByUserId(userId); + users.add(user); + } + for (String userName : getUserNames(userRefs)) { + User user = UserManager.getUserByName(Strings.unquote(userName)); + users.add(user); + } + } + return users; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/AbstractWorkflowArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/AbstractWorkflowArtifact.java new file mode 100644 index 00000000000..72ff4c48af1 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/AbstractWorkflowArtifact.java @@ -0,0 +1,822 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osee.ats.core.artifact.AbstractAtsArtifact; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.AbstractReviewArtifact; +import org.eclipse.osee.ats.core.review.ReviewManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.version.TargetedVersionUtil; +import org.eclipse.osee.ats.core.version.VersionArtifact; +import org.eclipse.osee.ats.core.workdef.RuleDefinitionOption; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workdef.WorkDefinition; +import org.eclipse.osee.ats.core.workdef.WorkDefinitionFactory; +import org.eclipse.osee.ats.core.workdef.WorkDefinitionMatch; +import org.eclipse.osee.ats.core.workflow.log.ArtifactLog; +import org.eclipse.osee.ats.core.workflow.log.AtsLog; +import org.eclipse.osee.ats.core.workflow.log.LogItem; +import org.eclipse.osee.ats.core.workflow.log.LogType; +import org.eclipse.osee.ats.core.workflow.note.ArtifactNote; +import org.eclipse.osee.ats.core.workflow.note.AtsNote; +import org.eclipse.osee.ats.core.workflow.transition.TransitionManager; +import org.eclipse.osee.framework.access.AccessControlManager; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.data.IRelationTypeSide; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.enums.DeletionFlag; +import org.eclipse.osee.framework.core.enums.PermissionEnum; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.core.services.CmAccessControl; +import org.eclipse.osee.framework.core.services.HasCmAccessControl; +import org.eclipse.osee.framework.core.util.IGroupExplorerProvider; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; +import org.eclipse.osee.framework.skynet.core.artifact.Attribute; +import org.eclipse.osee.framework.skynet.core.relation.RelationLink; +import org.eclipse.osee.framework.skynet.core.relation.RelationManager; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * @author Donald G. Dunne + */ +public abstract class AbstractWorkflowArtifact extends AbstractAtsArtifact implements HasCmAccessControl, IGroupExplorerProvider { + + private final Set<IRelationTypeSide> atsWorldRelations = new HashSet<IRelationTypeSide>(); + private Collection<User> transitionAssignees; + protected AbstractWorkflowArtifact parentAwa; + protected TeamWorkFlowArtifact parentTeamArt; + protected ActionArtifact parentAction; + private StateManager stateMgr; + private AtsLog atsLog; + private AtsNote atsNote; + private boolean inTransition = false; + private boolean targetedErrorLogged = false; + + public AbstractWorkflowArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + @Override + public void onBirth() throws OseeCoreException { + super.onBirth(); + if (getSoleAttributeValue(AtsAttributeTypes.CurrentStateType, null) == null) { + if (getSoleAttributeValue(AtsAttributeTypes.CurrentState, null) == null) { + setSoleAttributeValue(AtsAttributeTypes.CurrentState, ""); + } + if (isAttributeTypeValid(AtsAttributeTypes.CurrentStateType)) { + setSoleAttributeValue(AtsAttributeTypes.CurrentStateType, WorkPageType.Working.name()); + } + } + } + + @Override + public void onInitializationComplete() throws OseeCoreException { + super.onInitializationComplete(); + initializeSMA(); + } + + @SuppressWarnings("unused") + protected void initializeSMA() throws OseeCoreException { + initalizePreSaveCache(); + } + + public void initalizePreSaveCache() { + try { + stateMgr = new StateManager(this); + atsLog = new AtsLog(new ArtifactLog(this)); + atsNote = new AtsNote(new ArtifactNote(this)); + // TODO Add this back in + // AtsNotification.notifyNewAssigneesAndReset(this, true); + // AtsNotification.notifyOriginatorAndReset(this, true); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + public void initializeNewStateMachine(Collection<User> assignees, Date createdDate, User createdBy) throws OseeCoreException { + StateDefinition startState = getWorkDefinition().getStartState(); + initializeNewStateMachine(startState, assignees, createdDate, createdBy); + } + + public void initializeNewStateMachine(IWorkPage state, Collection<User> assignees, Date createdDate, User createdBy) throws OseeCoreException { + getStateMgr().initializeStateMachine(state, assignees); + setCreatedBy(createdBy, true, createdDate); + (new TransitionManager(this)).logStateStartedEvent(state, createdDate, createdBy); + } + + public boolean isTargetedVersionable() throws OseeCoreException { + if (!isTeamWorkflow()) { + return false; + } + return ((TeamWorkFlowArtifact) this).getTeamDefinition().getTeamDefinitionHoldingVersions() != null && ((TeamWorkFlowArtifact) this).getTeamDefinition().getTeamDefinitionHoldingVersions().isTeamUsesVersions(); + } + + public String getArtifactSuperTypeName() { + return getArtifactTypeName(); + } + + @SuppressWarnings("unused") + public Collection<User> getImplementers() throws OseeCoreException { + return Collections.emptyList(); + } + + @SuppressWarnings("unused") + public double getWorldViewWeeklyBenefit() throws OseeCoreException { + return 0; + } + + @Override + public void onAttributePersist(SkynetTransaction transaction) { + // Since multiple ways exist to change the assignees, notification is performed on the persist + if (isDeleted()) { + return; + } + try { + // TODO Add this back in + // AtsNotification.notifyNewAssigneesAndReset(this, false); + // AtsNotification.notifyOriginatorAndReset(this, false); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + } + + @SuppressWarnings("unused") + public boolean isValidationRequired() throws OseeCoreException { + return false; + } + + @Override + public String getDescription() { + return ""; + } + + @SuppressWarnings("unused") + public AbstractWorkflowArtifact getParentAWA() throws OseeCoreException { + return parentAwa; + } + + @SuppressWarnings("unused") + public Artifact getParentActionArtifact() throws OseeCoreException { + return parentAction; + } + + @SuppressWarnings("unused") + public TeamWorkFlowArtifact getParentTeamWorkflow() throws OseeCoreException { + return parentTeamArt; + } + + @SuppressWarnings("unused") + public String getEditorTitle() throws OseeCoreException { + return getType() + ": " + getName(); + } + + /** + * Registers relation as part of the parent/child hierarchy in ATS World + */ + public void registerAtsWorldRelation(IRelationTypeSide typeSideToken) { + atsWorldRelations.add(typeSideToken); + } + + public void clearCaches() { + implementersStr = null; + } + + public void atsDelete(Set<Artifact> deleteArts, Map<Artifact, Object> allRelated) throws OseeCoreException { + deleteArts.add(this); + for (Artifact relative : getBSideArtifacts()) { + allRelated.put(relative, this); + } + } + + private List<Artifact> getBSideArtifacts() throws OseeCoreException { + List<Artifact> sideBArtifacts = new ArrayList<Artifact>(); + List<RelationLink> relatives = getRelationsAll(DeletionFlag.EXCLUDE_DELETED); + for (RelationLink link : relatives) { + Artifact sideB = link.getArtifactB(); + if (!sideB.equals(this)) { + sideBArtifacts.add(sideB); + } + } + + return sideBArtifacts; + } + + public String getType() { + return getArtifactTypeName(); + } + + public String getCurrentStateName() { + return getStateMgr().getCurrentStateName(); + } + + public boolean isInState(IWorkPage state) { + return getStateMgr().isInState(state); + } + + public String implementersStr = null; + + public double getEstimatedHoursFromArtifact() throws OseeCoreException { + if (isAttributeTypeValid(AtsAttributeTypes.EstimatedHours)) { + return getSoleAttributeValue(AtsAttributeTypes.EstimatedHours, 0.0); + } + return 0; + } + + public double getEstimatedHoursFromTasks(IWorkPage relatedToState) throws OseeCoreException { + if (!(this instanceof AbstractTaskableArtifact)) { + return 0; + } + return ((AbstractTaskableArtifact) this).getEstimatedHoursFromTasks(relatedToState); + } + + public double getEstimatedHoursFromTasks() throws OseeCoreException { + if (!(this instanceof AbstractTaskableArtifact)) { + return 0; + } + return ((AbstractTaskableArtifact) this).getEstimatedHoursFromTasks(); + } + + public double getEstimatedHoursFromReviews() throws OseeCoreException { + if (isTeamWorkflow()) { + return ReviewManager.getEstimatedHours((TeamWorkFlowArtifact) this); + } + return 0; + } + + public double getEstimatedHoursFromReviews(IWorkPage relatedToState) throws OseeCoreException { + if (isTeamWorkflow()) { + return ReviewManager.getEstimatedHours((TeamWorkFlowArtifact) this, relatedToState); + } + return 0; + } + + public double getEstimatedHoursTotal(IWorkPage relatedToState) throws OseeCoreException { + return getEstimatedHoursFromArtifact() + getEstimatedHoursFromTasks(relatedToState) + getEstimatedHoursFromReviews(relatedToState); + } + + public double getEstimatedHoursTotal() throws OseeCoreException { + return getEstimatedHoursFromArtifact() + getEstimatedHoursFromTasks() + getEstimatedHoursFromReviews(); + } + + public double getRemainHoursFromArtifact() throws OseeCoreException { + if (isCompleted() || isCancelled()) { + return 0; + } + double est = getSoleAttributeValue(AtsAttributeTypes.EstimatedHours, 0.0); + if (est == 0) { + return getEstimatedHoursFromArtifact(); + } + return est - est * PercentCompleteTotalUtil.getPercentCompleteTotal(this) / 100.0; + } + + public double getRemainHoursTotal() throws OseeCoreException { + return getRemainHoursFromArtifact() + getRemainFromTasks() + getRemainFromReviews(); + } + + public double getRemainFromTasks() throws OseeCoreException { + if (!(this instanceof AbstractTaskableArtifact)) { + return 0; + } + return ((AbstractTaskableArtifact) this).getRemainHoursFromTasks(); + } + + public double getRemainFromReviews() throws OseeCoreException { + if (isTeamWorkflow()) { + return ReviewManager.getRemainHours((TeamWorkFlowArtifact) this); + } + return 0; + } + + @SuppressWarnings("unused") + public double getManHrsPerDayPreference() throws OseeCoreException { + return AtsUtilCore.DEFAULT_HOURS_PER_WORK_DAY; + } + + /** + * Return true if this artifact, it's ATS relations and any of the other side artifacts are dirty + * + * @return true if any object in SMA tree is dirty + */ + public Result isSMAEditorDirty() { + try { + Set<Artifact> artifacts = new HashSet<Artifact>(); + getSmaArtifactsOneLevel(this, artifacts); + for (Artifact artifact : artifacts) { + if (artifact.isDirty()) { + String rString = null; + for (Attribute<?> attribute : artifact.internalGetAttributes()) { + if (attribute.isDirty()) { + rString = "Attribute: " + attribute.getNameValueDescription(); + break; + } + } + + if (rString == null) { + rString = RelationManager.reportHasDirtyLinks(artifact); + } + return new Result(true, String.format("Artifact [%s][%s] is dirty\n\n%s", artifact.getHumanReadableId(), + artifact, rString)); + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't save artifact " + getHumanReadableId(), ex); + } + return Result.FalseResult; + } + + public void saveSMA(SkynetTransaction transaction) { + try { + Set<Artifact> artifacts = new HashSet<Artifact>(); + getSmaArtifactsOneLevel(this, artifacts); + for (Artifact artifact : artifacts) { + artifact.persist(transaction); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't save artifact " + getHumanReadableId(), ex); + } + } + + public void revertSMA() { + try { + Set<Artifact> artifacts = new HashSet<Artifact>(); + getSmaArtifactsOneLevel(this, artifacts); + for (Artifact artifact : artifacts) { + artifact.reloadAttributesAndRelations(); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't revert artifact " + getHumanReadableId(), ex); + } + } + + @SuppressWarnings("unused") + public void getSmaArtifactsOneLevel(AbstractWorkflowArtifact smaArtifact, Set<Artifact> artifacts) throws OseeCoreException { + artifacts.add(smaArtifact); + } + + /** + * Called at the end of a transition just before transaction manager persist. SMAs can override to perform tasks due + * to transition. + */ + @SuppressWarnings("unused") + public void transitioned(StateDefinition fromState, StateDefinition toState, Collection<User> toAssignees, boolean persist, SkynetTransaction transaction) throws OseeCoreException { + // provided for subclass implementation + } + + @Override + public Artifact getParentAtsArtifact() throws OseeCoreException { + return getParentAWA(); + } + + /** + * Return Percent Complete ONLY on tasks related to stateName. Total Percent / # Tasks + */ + public int getPercentCompleteSMAStateTasks(IWorkPage state) throws OseeCoreException { + if (!(this instanceof AbstractTaskableArtifact)) { + return 0; + } + return ((AbstractTaskableArtifact) this).getPercentCompleteFromTasks(state); + } + + public Set<IRelationTypeSide> getAtsWorldRelations() { + return atsWorldRelations; + } + + public String getWorldViewLastUpdated() throws OseeCoreException { + return DateUtil.getMMDDYYHHMM(getLastModified()); + } + + @SuppressWarnings("unused") + public String getWorldViewSWEnhancement() throws OseeCoreException { + return ""; + } + + @Override + public String getGroupExplorerName() { + return String.format("[%s] %s", getStateMgr().getCurrentStateName(), getName()); + } + + public AtsLog getLog() { + return atsLog; + } + + public AtsNote getNotes() { + return atsNote; + } + + public Result getUserInputNeeded() { + return Result.FalseResult; + } + + public WorkDefinition getWorkDefinition() { + return getWorkDefinitionMatch().getWorkDefinition(); + } + + public WorkDefinitionMatch getWorkDefinitionMatch() { + try { + return WorkDefinitionFactory.getWorkDefinition(this); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return null; + } + + public StateDefinition getStateDefinition() { + if (getStateMgr().getCurrentStateName() == null) { + return null; + } + return getWorkDefinition().getStateByName(getStateMgr().getCurrentStateName()); + } + + public StateDefinition getStateDefinitionByName(String name) { + return getWorkDefinition().getStateByName(name); + } + + public boolean isHistoricalVersion() { + return isHistorical(); + } + + public List<StateDefinition> getToStates() { + return getStateDefinition().getToStates(); + } + + public boolean isAccessControlWrite() throws OseeCoreException { + return AccessControlManager.hasPermission(this, PermissionEnum.WRITE); + } + + /** + * @return true if this is a TeamWorkflow and it uses versions + */ + public boolean isTeamUsesVersions() { + if (!isTeamWorkflow()) { + return false; + } + try { + return ((TeamWorkFlowArtifact) this).getTeamDefinition().isTeamUsesVersions(); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return false; + } + } + + /** + * Return true if awa is TeamWorkflowArtifact or review of a team workflow and it's TeamDefinitionArtifact has rule + * set + */ + public boolean teamDefHasRule(RuleDefinitionOption option) throws OseeCoreException { + TeamWorkFlowArtifact teamArt = null; + if (isTeamWorkflow()) { + teamArt = (TeamWorkFlowArtifact) this; + } + if (this instanceof AbstractReviewArtifact) { + teamArt = ((AbstractReviewArtifact) this).getParentTeamWorkflow(); + } + if (teamArt == null) { + return false; + } + try { + return teamArt.getTeamDefinition().hasRule(option); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + return false; + } + } + + /** + * @return true if this is a TeamWorkflow and the version it's been targeted for has been released + */ + public boolean isReleased() { + try { + VersionArtifact verArt = getTargetedVersion(); + if (verArt != null) { + return verArt.isReleased(); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return false; + } + + public boolean isVersionLocked() { + try { + VersionArtifact verArt = getTargetedVersion(); + if (verArt != null) { + return verArt.isVersionLocked(); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return false; + } + + public VersionArtifact getTargetedVersion() throws OseeCoreException { + return TargetedVersionUtil.getTargetedVersion(this); + } + + public String getTargetedVersionStr() throws OseeCoreException { + return TargetedVersionUtil.getTargetedVersionStr(this); + } + + public void setCreatedBy(User user, boolean logChange, Date date) throws OseeCoreException { + if (logChange) { + if (getSoleAttributeValue(AtsAttributeTypes.CreatedBy, null) == null) { + atsLog.addLog(LogType.Originated, "", "", date, user); + } else { + atsLog.addLog(LogType.Originated, "", "Changed by " + UserManager.getUser().getName(), date, user); + atsLog.internalResetOriginator(user); + } + } + if (isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + setSoleAttributeValue(AtsAttributeTypes.CreatedBy, user.getUserId()); + } + if (isAttributeTypeValid(AtsAttributeTypes.CreatedDate)) { + setSoleAttributeValue(AtsAttributeTypes.CreatedDate, date); + } + } + + public void internalSetCreatedBy(User user) throws OseeCoreException { + atsLog.internalResetOriginator(user); + if (isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + setSoleAttributeValue(AtsAttributeTypes.CreatedBy, user.getUserId()); + } + } + + public void internalSetCreatedDate(Date date) throws OseeCoreException { + atsLog.internalResetCreatedDate(date); + if (isAttributeTypeValid(AtsAttributeTypes.CreatedDate)) { + setSoleAttributeValue(AtsAttributeTypes.CreatedDate, date); + } + } + + public Date getCreatedDate() throws OseeCoreException { + Date date = getSoleAttributeValue(AtsAttributeTypes.CreatedDate, null); + if (date == null) { + // Keep this for backward compatibility + return getLog().internalGetCreationDate(); + } + return date; + } + + public User getCreatedBy() throws OseeCoreException { + String userId = getSoleAttributeValue(AtsAttributeTypes.CreatedBy, null); + if (!Strings.isValid(userId)) { + return getLog().internalGetOriginator(); + } else { + return UserManager.getUserByUserId(userId); + } + } + + public Date internalGetCancelledDate() throws OseeCoreException { + Date date = getSoleAttributeValue(AtsAttributeTypes.CancelledDate, null); + if (date == null) { + // Keep this for backward compatibility + LogItem item = getLog().internalGetCancelledLogItem(); + if (item != null) { + return item.getDate(); + } + return null; + } + return date; + } + + public User getCancelledBy() throws OseeCoreException { + String userId = getSoleAttributeValue(AtsAttributeTypes.CancelledBy, null); + if (!Strings.isValid(userId)) { + // Keep this for backward compatibility + LogItem item = getLog().internalGetCancelledLogItem(); + if (item != null) { + return item.getUser(); + } + return null; + } else { + return UserManager.getUserByUserId(userId); + } + } + + public String getCancelledReason() throws OseeCoreException { + String reason = getSoleAttributeValue(AtsAttributeTypes.CancelledReason, null); + if (!Strings.isValid(reason)) { + reason = getLog().internalGetCancelledReason(); + } + return reason; + } + + public void setCancellationReason(String reason) throws OseeCoreException { + // Keep this for backward compatibility + getLog().internalSetCancellationReason(reason); + if (isAttributeTypeValid(AtsAttributeTypes.CancelledReason)) { + setSoleAttributeValue(AtsAttributeTypes.CancelledReason, reason); + } + } + + public String getCancelledFromState() throws OseeCoreException { + String fromState = getSoleAttributeValue(AtsAttributeTypes.CancelledFromState, null); + if (!Strings.isValid(fromState)) { + // Keep this for backward compatibility + return getLog().internalGetCancelledFromState(); + } + return fromState; + } + + public Date getCompletedDate() throws OseeCoreException { + Date date = getSoleAttributeValue(AtsAttributeTypes.CompletedDate, null); + if (date == null) { + // Keep this for backward compatibility + LogItem item = getLog().internalGetCompletedLogItem(); + if (item != null) { + return item.getDate(); + } + return null; + } + return date; + } + + public User getCompletedBy() throws OseeCoreException { + String userId = getSoleAttributeValue(AtsAttributeTypes.CompletedBy, null); + if (!Strings.isValid(userId)) { + // Keep this for backward compatibility + LogItem item = getLog().internalGetCompletedLogItem(); + if (item != null) { + return item.getUser(); + } + return null; + } else { + return UserManager.getUserByUserId(userId); + } + } + + public LogItem getStateCompletedData(IWorkPage state) throws OseeCoreException { + return getLog().getStateEvent(LogType.StateComplete, state.getPageName()); + } + + public LogItem getStateCancelledData(IWorkPage state) throws OseeCoreException { + return getLog().getStateEvent(LogType.StateCancelled, state.getPageName()); + } + + public LogItem getStateStartedData(IWorkPage state) throws OseeCoreException { + return getLog().getStateEvent(LogType.StateEntered, state.getPageName()); + } + + public String getCompletedFromState() throws OseeCoreException { + String fromState = getSoleAttributeValue(AtsAttributeTypes.CompletedFromState, null); + if (!Strings.isValid(fromState)) { + return getLog().internalGetCompletedFromState(); + } + return fromState; + } + + public boolean isInWork() throws OseeCoreException { + // Backward compatibility; remove this once 0.9.7 released + if (isAttributeTypeValid(AtsAttributeTypes.CurrentStateType) && getSoleAttributeValue( + AtsAttributeTypes.CurrentStateType, null) != null) { + return getSoleAttributeValue(AtsAttributeTypes.CurrentStateType, "").equals(WorkPageType.Working.name()); + } else { + return !isCompletedOrCancelled(); + } + + } + + public boolean isCompleted() throws OseeCoreException { + if (isAttributeTypeValid(AtsAttributeTypes.CurrentStateType) && getSoleAttributeValue( + AtsAttributeTypes.CurrentStateType, null) != null) { + return getSoleAttributeValue(AtsAttributeTypes.CurrentStateType, "").equals(WorkPageType.Completed.name()); + } else { + return getCurrentStateName().equals(TeamState.Completed.getPageName()); + } + } + + public boolean isCancelled() throws OseeCoreException { + // Backward compatibility; remove this once 0.9.7 released + if (isAttributeTypeValid(AtsAttributeTypes.CurrentStateType) && getSoleAttributeValue( + AtsAttributeTypes.CurrentStateType, null) != null) { + return getSoleAttributeValue(AtsAttributeTypes.CurrentStateType, "").equals(WorkPageType.Cancelled.name()); + } else { + return getCurrentStateName().equals(TeamState.Cancelled.getPageName()); + } + } + + public boolean isCompletedOrCancelled() throws OseeCoreException { + return isCompleted() || isCancelled(); + } + + public void setTransitionAssignees(Collection<User> assignees) throws OseeCoreException { + if (assignees.contains(UserManager.getUser(SystemUser.OseeSystem)) || assignees.contains(UserManager.getUser(SystemUser.Guest))) { + throw new OseeArgumentException("Can not assign workflow to OseeSystem or Guest"); + } + if (assignees.size() > 1 && assignees.contains(UserManager.getUser(SystemUser.UnAssigned))) { + throw new OseeArgumentException("Can not assign to user and UnAssigned"); + } + transitionAssignees = assignees; + } + + public boolean isAssigneeMe() throws OseeCoreException { + return stateMgr.getAssignees().contains(UserManager.getUser()); + } + + public Collection<User> getTransitionAssignees() throws OseeCoreException { + if (transitionAssignees != null) { + if (!transitionAssignees.isEmpty() && transitionAssignees.contains(UserManager.getUser(SystemUser.UnAssigned))) { + transitionAssignees.remove(UserManager.getUser(SystemUser.UnAssigned)); + } + if (!transitionAssignees.isEmpty()) { + return transitionAssignees; + } + } + return stateMgr.getAssignees(); + } + + public String getTransitionAssigneesStr() throws OseeCoreException { + return Artifacts.toTextList(getTransitionAssignees(), ";"); + } + + public boolean isInTransition() { + return inTransition; + } + + public void setInTransition(boolean inTransition) { + this.inTransition = inTransition; + } + + public StateManager getStateMgr() { + return stateMgr; + } + + public boolean isTeamWorkflow() { + return this.isOfType(AtsArtifactTypes.TeamWorkflow); + } + + public boolean isTask() { + return this.isOfType(AtsArtifactTypes.Task); + } + + public boolean isReview() { + return this instanceof AbstractReviewArtifact; + } + + protected void addPriviledgedUsersUpTeamDefinitionTree(TeamDefinitionArtifact tda, Set<User> users) throws OseeCoreException { + users.addAll(tda.getLeads()); + users.addAll(tda.getPrivilegedMembers()); + + // Walk up tree to get other editors + if (tda.getParent() != null && tda.getParent() instanceof TeamDefinitionArtifact) { + addPriviledgedUsersUpTeamDefinitionTree((TeamDefinitionArtifact) tda.getParent(), users); + } + } + + @Override + public CmAccessControl getAccessControl() { + Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID); + BundleContext context = bundle.getBundleContext(); + ServiceReference reference = context.getServiceReference(CmAccessControl.class.getName()); + return (CmAccessControl) context.getService(reference); + } + + public boolean isTargetedErrorLogged() { + return targetedErrorLogged; + } + + public void setTargetedErrorLogged(boolean targetedErrorLogged) { + this.targetedErrorLogged = targetedErrorLogged; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifact.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifact.java new file mode 100644 index 00000000000..e40fb64d878 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifact.java @@ -0,0 +1,45 @@ +/* + * Created on Mar 24, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.osee.ats.core.config.ActionableItemArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.model.Branch; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactFactory; + +public class ActionArtifact extends Artifact { + + public ActionArtifact(ArtifactFactory parentFactory, String guid, String humanReadableId, Branch branch, IArtifactType artifactType) throws OseeCoreException { + super(parentFactory, guid, humanReadableId, branch, artifactType); + } + + public Set<ActionableItemArtifact> getActionableItems() throws OseeCoreException { + Set<ActionableItemArtifact> aias = new HashSet<ActionableItemArtifact>(); + for (TeamWorkFlowArtifact team : getTeams()) { + aias.addAll(team.getActionableItemsDam().getActionableItems()); + } + return aias; + } + + public Collection<TeamWorkFlowArtifact> getTeams() throws OseeCoreException { + return getRelatedArtifactsUnSorted(AtsRelationTypes.ActionToWorkflow_WorkFlow, TeamWorkFlowArtifact.class); + } + + public TeamWorkFlowArtifact getFirstTeam() throws OseeCoreException { + if (getRelatedArtifactsCount(AtsRelationTypes.ActionToWorkflow_WorkFlow) > 0) { + return getTeams().iterator().next(); + } + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifactRollup.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifactRollup.java new file mode 100644 index 00000000000..d8f8b2e2256 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionArtifactRollup.java @@ -0,0 +1,148 @@ +/* + * Created on Mar 7, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +public class ActionArtifactRollup { + + private final ActionArtifact action; + private final SkynetTransaction transaction; + + public ActionArtifactRollup(ActionArtifact action, SkynetTransaction transaction) throws OseeArgumentException { + this.action = action; + this.transaction = transaction; + if (!action.isOfType(AtsArtifactTypes.Action)) { + throw new OseeArgumentException("Artifact must be an Action instead of [%s]", action.getArtifactTypeName()); + } + } + + public void resetAttributesOffChildren() throws OseeCoreException { + resetChangeTypeOffChildren(action); + resetPriorityOffChildren(); + resetUserCommunityOffChildren(); + resetTitleOffChildren(); + resetValidationOffChildren(); + resetDescriptionOffChildren(); + action.persist(transaction); + } + + public static void resetChangeTypeOffChildren(Artifact actionArt) throws OseeCoreException { + if (!actionArt.isOfType(AtsArtifactTypes.Action)) { + throw new OseeArgumentException("Artifact must be an Action instead of [%s]", actionArt.getArtifactTypeName()); + } + ChangeType changeType = null; + Collection<TeamWorkFlowArtifact> teamArts = ActionManagerCore.getTeams(actionArt); + if (teamArts.size() == 1) { + changeType = ChangeTypeUtil.getChangeType(teamArts.iterator().next()); + } else { + for (TeamWorkFlowArtifact team : teamArts) { + if (!team.isCancelled()) { + if (changeType == null) { + changeType = ChangeTypeUtil.getChangeType(team); + } else if (changeType != ChangeTypeUtil.getChangeType(team)) { + return; + } + } + } + } + if (changeType != null && ChangeTypeUtil.getChangeType(actionArt) != changeType) { + ChangeTypeUtil.setChangeType(actionArt, changeType); + } + } + + /** + * Reset Action title only if all children are titled the same + */ + private void resetTitleOffChildren() throws OseeCoreException { + String title = ""; + for (TeamWorkFlowArtifact team : action.getTeams()) { + if (title.isEmpty()) { + title = team.getName(); + } else if (!title.equals(team.getName())) { + return; + } + } + if (!title.equals(action.getName())) { + action.setName(title); + } + } + + // Set validation to true if any require validation + private void resetValidationOffChildren() throws OseeCoreException { + boolean validationRequired = false; + for (TeamWorkFlowArtifact team : action.getTeams()) { + if (team.getSoleAttributeValue(AtsAttributeTypes.ValidationRequired, false)) { + validationRequired = true; + } + } + if (validationRequired != action.getSoleAttributeValue(AtsAttributeTypes.ValidationRequired, false)) { + action.setSoleAttributeValue(AtsAttributeTypes.ValidationRequired, validationRequired); + } + } + + /** + * Reset Action title only if all children are titled the same + */ + private void resetDescriptionOffChildren() throws OseeCoreException { + String desc = ""; + for (TeamWorkFlowArtifact team : action.getTeams()) { + if (desc.isEmpty()) { + desc = team.getSoleAttributeValue(AtsAttributeTypes.Description, ""); + } else if (!desc.equals(team.getSoleAttributeValue(AtsAttributeTypes.Description, ""))) { + return; + } + } + if (!desc.equals(action.getSoleAttributeValue(AtsAttributeTypes.Description, ""))) { + action.setSoleAttributeValue(AtsAttributeTypes.Description, desc); + } + if (desc.isEmpty()) { + action.deleteSoleAttribute(AtsAttributeTypes.Description); + } + } + + private void resetPriorityOffChildren() throws OseeCoreException { + String priorityType = null; + Collection<TeamWorkFlowArtifact> teamArts = action.getTeams(); + if (teamArts.size() == 1) { + priorityType = PriorityUtil.getPriorityStr(teamArts.iterator().next()); + } else { + for (TeamWorkFlowArtifact team : teamArts) { + if (!team.isCancelled()) { + if (priorityType == null) { + priorityType = PriorityUtil.getPriorityStr(team); + } else if (!priorityType.equals(PriorityUtil.getPriorityStr(team))) { + return; + } + } + } + } + if (Strings.isValid(priorityType)) { + action.setSoleAttributeValue(AtsAttributeTypes.PriorityType, priorityType); + } + } + + private void resetUserCommunityOffChildren() throws OseeCoreException { + Set<String> userComs = new HashSet<String>(); + for (TeamWorkFlowArtifact team : action.getTeams()) { + if (!team.isCancelled()) { + userComs.addAll(team.getAttributesToStringList(AtsAttributeTypes.UserCommunity)); + } + } + action.setAttributeValues(AtsAttributeTypes.UserCommunity, userComs); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionManagerCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionManagerCore.java new file mode 100644 index 00000000000..609e37e75ad --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionManagerCore.java @@ -0,0 +1,36 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsRelationTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class ActionManagerCore { + + public static Collection<TeamWorkFlowArtifact> getTeams(Object object) throws OseeCoreException { + if (object instanceof Artifact && ((Artifact) object).isOfType(AtsArtifactTypes.Action)) { + return ((Artifact) object).getRelatedArtifacts(AtsRelationTypes.ActionToWorkflow_WorkFlow, + TeamWorkFlowArtifact.class); + } + return java.util.Collections.emptyList(); + } + + public static TeamWorkFlowArtifact getFirstTeam(Object object) throws OseeCoreException { + Collection<TeamWorkFlowArtifact> arts = getTeams(object); + if (arts.size() > 0) { + return arts.iterator().next(); + } + return null; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionableItemManagerCore.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionableItemManagerCore.java new file mode 100644 index 00000000000..747de313b91 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ActionableItemManagerCore.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.config.ActionableItemArtifact; +import org.eclipse.osee.ats.core.config.AtsArtifactToken; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.config.TeamDefinitionManager; +import org.eclipse.osee.ats.core.config.TeamDefinitionManagerCore; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.AtsCacheManager; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.enums.Active; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.jdk.core.util.Collections; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.ArtifactCache; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; + +/** + * @author Donald G. Dunne + */ +public class ActionableItemManagerCore { + + private final Artifact artifact; + + public ActionableItemManagerCore(Artifact artifact) { + this.artifact = artifact; + } + + public Set<ActionableItemArtifact> getActionableItems() throws OseeCoreException { + Set<ActionableItemArtifact> ais = new HashSet<ActionableItemArtifact>(); + for (String guid : getActionableItemGuids()) { + try { + ActionableItemArtifact aia = + (ActionableItemArtifact) ArtifactCache.getActive(guid, AtsUtilCore.getAtsBranch()); + if (aia == null) { + OseeLog.log(Activator.class, Level.SEVERE, "Can't find Actionable Item for guid " + guid); + } else { + ais.add(aia); + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, "Error getting actionable item for guid " + guid, ex); + } + } + return ais; + } + + public String getActionableItemsStr() throws OseeCoreException { + return Artifacts.toString("; ", getActionableItems()); + } + + public List<String> getActionableItemGuids() throws OseeCoreException { + return artifact.getAttributesToStringList(AtsAttributeTypes.ActionableItem); + } + + public void addActionableItem(ActionableItemArtifact aia) throws OseeCoreException { + if (!getActionableItemGuids().contains(aia.getGuid())) { + artifact.addAttribute(AtsAttributeTypes.ActionableItem, aia.getGuid()); + } + } + + public void removeActionableItem(ActionableItemArtifact aia) throws OseeCoreException { + artifact.deleteAttribute(AtsAttributeTypes.ActionableItem, aia.getGuid()); + } + + public Result setActionableItems(Collection<ActionableItemArtifact> newItems) throws OseeCoreException { + Set<ActionableItemArtifact> existingAias = getActionableItems(); + + // Remove non-selected items + for (ActionableItemArtifact existingAia : existingAias) { + if (!newItems.contains(existingAia)) { + removeActionableItem(existingAia); + } + } + + // Add newly-selected items + for (ActionableItemArtifact newItem : newItems) { + if (!existingAias.contains(newItem)) { + addActionableItem(newItem); + } + } + + return Result.TrueResult; + } + + public static Set<TeamDefinitionArtifact> getTeamsFromItemAndChildren(ActionableItemArtifact aia) throws OseeCoreException { + return TeamDefinitionManager.getTeamsFromItemAndChildren(aia); + } + + public static Set<ActionableItemArtifact> getActionableItemsFromItemAndChildren(ActionableItemArtifact aia) throws OseeCoreException { + Set<ActionableItemArtifact> aias = new HashSet<ActionableItemArtifact>(); + getActionableItemsFromItemAndChildren(aia, aias); + return aias; + } + + public static void getActionableItemsFromItemAndChildren(ActionableItemArtifact aia, Set<ActionableItemArtifact> aiaTeams) throws OseeCoreException { + for (Artifact art : aia.getChildren()) { + if (art instanceof ActionableItemArtifact) { + aiaTeams.add((ActionableItemArtifact) art); + for (Artifact childArt : aia.getChildren()) { + if (childArt instanceof ActionableItemArtifact) { + getActionableItemsFromItemAndChildren((ActionableItemArtifact) childArt, aiaTeams); + } + } + } + } + } + + public static Set<ActionableItemArtifact> getActionableItems(Collection<String> actionableItemNames) { + Set<ActionableItemArtifact> aias = new HashSet<ActionableItemArtifact>(); + for (String actionableItemName : actionableItemNames) { + for (Artifact artifact : AtsCacheManager.getArtifactsByName(AtsArtifactTypes.ActionableItem, + actionableItemName)) { + aias.add((ActionableItemArtifact) artifact); + } + } + return aias; + } + + public static Collection<TeamDefinitionArtifact> getImpactedTeamDefs(Collection<ActionableItemArtifact> aias) throws OseeCoreException { + return TeamDefinitionManagerCore.getImpactedTeamDefs(aias); + } + + public static List<ActionableItemArtifact> getActionableItems(Active active) throws OseeCoreException { + return Collections.castAll(AtsCacheManager.getArtifactsByActive(AtsArtifactTypes.ActionableItem, active)); + } + + public static String getNotActionableItemError(Artifact aia) { + return "Action can not be written against " + aia.getArtifactTypeName() + " \"" + aia + "\" (" + aia.getHumanReadableId() + ").\n\nChoose another item."; + } + + public static ActionableItemArtifact getTopActionableItem() { + return (ActionableItemArtifact) AtsUtilCore.getFromToken(AtsArtifactToken.TopActionableItem); + } + + public static List<ActionableItemArtifact> getActionableItemsAll() throws OseeCoreException { + return Collections.castAll(AtsCacheManager.getArtifactsByActive(AtsArtifactTypes.ActionableItem, Active.Both)); + } + + public static List<ActionableItemArtifact> getTopLevelActionableItems(Active active) throws OseeCoreException { + ActionableItemArtifact topAi = getTopActionableItem(); + if (topAi == null) { + return java.util.Collections.emptyList(); + } + return Collections.castAll(AtsUtilCore.getActive( + Artifacts.getChildrenOfTypeSet(topAi, ActionableItemArtifact.class, false), active, + ActionableItemArtifact.class)); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeType.java new file mode 100644 index 00000000000..f4f970abee2 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeType.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.ArrayList; + +/** + * @author Donald G. Dunne + */ +public enum ChangeType { + + None, + Support, + Problem, + Improvement, + Refinement; + + public static String[] getChangeTypes() { + ArrayList<String> types = new ArrayList<String>(); + for (ChangeType type : values()) { + if (type != None) { + types.add(type.name()); + } + } + return types.toArray(new String[types.size()]); + } + + public static ChangeType getChangeType(String name) { + for (ChangeType type : values()) { + if (type.name().equals(name)) { + return type; + } + } + return None; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeTypeUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeTypeUtil.java new file mode 100644 index 00000000000..97bef53354d --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ChangeTypeUtil.java @@ -0,0 +1,37 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class ChangeTypeUtil { + + public static String getChangeTypeStr(Artifact artifact) throws OseeCoreException { + ChangeType changeType = getChangeType(artifact); + if (changeType == ChangeType.None) { + return ""; + } + return changeType.name(); + } + + public static ChangeType getChangeType(Artifact artifact) throws OseeCoreException { + return ChangeType.getChangeType(artifact.getSoleAttributeValue(AtsAttributeTypes.ChangeType, "")); + } + + public static void setChangeType(Artifact artifact, ChangeType changeType) throws OseeCoreException { + if (changeType == ChangeType.None) { + artifact.deleteSoleAttribute(AtsAttributeTypes.ChangeType); + } else { + artifact.setSoleAttributeValue(AtsAttributeTypes.ChangeType, changeType.name()); + } + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/EstimatedHoursUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/EstimatedHoursUtil.java new file mode 100644 index 00000000000..d287d440b7d --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/EstimatedHoursUtil.java @@ -0,0 +1,31 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; + +/** + * @author Donald G. Dunne + */ +public class EstimatedHoursUtil { + + public static double getEstimatedHours(Object object) throws OseeCoreException { + if (object instanceof AbstractWorkflowArtifact) { + return ((AbstractWorkflowArtifact) object).getEstimatedHoursTotal(); + } else if (Artifacts.isOfType(object, AtsArtifactTypes.Action)) { + double total = 0; + for (Artifact team : ActionManagerCore.getTeams(object)) { + total += getEstimatedHours(team); + } + return total; + } + return 0.0; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/HoursSpentUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/HoursSpentUtil.java new file mode 100644 index 00000000000..5fa472cf7d3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/HoursSpentUtil.java @@ -0,0 +1,185 @@ +/* + * Created on May 11, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.review.ReviewManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.task.TaskArtifact; +import org.eclipse.osee.ats.core.team.SimpleTeamState; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowManager; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.util.WorkflowManagerCore; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class HoursSpentUtil { + + /** + * Return hours spent working states, reviews and tasks (not children SMAs) + */ + public static double getHoursSpentTotal(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + double hours = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + hours += getHoursSpentTotal(team); + } + } + return hours; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getHoursSpentTotal(artifact, new StateManager((AbstractWorkflowArtifact) artifact).getCurrentState()); + } + return 0; + } + + /** + * Return hours spent working all states, reviews and tasks (not children SMAs) + */ + public static double getHoursSpentTotal(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + AbstractWorkflowArtifact awa = (AbstractWorkflowArtifact) artifact; + double hours = 0.0; + for (String stateName : awa.getStateMgr().getVisitedStateNames()) { + hours += getHoursSpentStateTotal(awa, new SimpleTeamState(stateName, WorkPageType.Working)); + } + return hours; + } + return 0; + } + + /** + * Return hours spent working SMA state, state tasks and state reviews (not children SMAs) + */ + public static double getHoursSpentStateTotal(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + double hours = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + hours += getHoursSpentStateTotal(team); + } + } + return hours; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getHoursSpentStateTotal(artifact, WorkflowManagerCore.getStateManager(artifact).getCurrentState()); + } + return 0; + } + + /** + * Return hours spent working SMA state, state tasks and state reviews (not children SMAs) + */ + public static double getHoursSpentStateTotal(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + AbstractWorkflowArtifact awa = WorkflowManagerCore.cast(artifact); + return getHoursSpentSMAState(awa, state) + getHoursSpentFromStateTasks(awa, state) + getHoursSpentStateReview( + awa, state); + } + return 0; + } + + /** + * Return hours spent working ONLY the SMA stateName (not children SMAs) + */ + public static double getHoursSpentStateReview(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + double hours = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + hours += getHoursSpentStateReview(team); + } + } + return hours; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getHoursSpentStateReview(artifact, WorkflowManagerCore.getStateManager(artifact).getCurrentState()); + } + return 0; + } + + /** + * Return hours spent working ONLY the SMA stateName (not children SMAs) + */ + public static double getHoursSpentStateReview(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.TeamWorkflow)) { + return ReviewManager.getHoursSpent(TeamWorkFlowManager.cast(artifact), state); + } + return 0; + } + + /** + * Return hours spent working ONLY the SMA stateName (not children SMAs) + */ + public static double getHoursSpentSMAState(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + double hours = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + hours += getHoursSpentSMAState(team); + } + } + return hours; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getHoursSpentSMAState(artifact, WorkflowManagerCore.getStateManager(artifact).getCurrentState()); + } + return 0; + } + + /** + * Return hours spent working ONLY the SMA stateName (not children SMAs) + */ + public static double getHoursSpentSMAState(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return WorkflowManagerCore.getStateManager(artifact).getHoursSpent(state); + } + return 0; + } + + /** + * Return hours spent working ONLY on tasks related to stateName + */ + public static double getHoursSpentFromStateTasks(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + double hours = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + hours += getHoursSpentFromStateTasks(team); + } + } + return hours; + } + if (artifact instanceof AbstractTaskableArtifact) { + return getHoursSpentFromStateTasks(artifact, + ((AbstractWorkflowArtifact) artifact).getStateMgr().getCurrentState()); + } + return 0; + } + + /** + * Return Hours Spent for Tasks of "Related to State" stateName + * + * @param relatedToState state name of parent workflow's state + * @return Returns the Hours Spent + */ + public static double getHoursSpentFromStateTasks(Artifact artifact, IWorkPage relatedToState) throws OseeCoreException { + double spent = 0; + if (artifact instanceof AbstractTaskableArtifact) { + for (TaskArtifact taskArt : ((AbstractTaskableArtifact) artifact).getTaskArtifacts(relatedToState)) { + spent += HoursSpentUtil.getHoursSpentTotal(taskArt); + } + } + return spent; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ITeamWorkflowProvider.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ITeamWorkflowProvider.java new file mode 100644 index 00000000000..760079f3c95 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/ITeamWorkflowProvider.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import org.eclipse.osee.ats.core.config.ActionableItemArtifact; +import org.eclipse.osee.ats.core.config.TeamDefinitionArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.framework.core.data.IArtifactType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; + +/** + * @author Donald G. Dunne + */ +public interface ITeamWorkflowProvider { + + /** + * Return true if this class/plugin is responsible for the creation of the Team Workflow that will be created for the + * given Team Definition. This should be a light-weight check. + * + * @param teamDef related to the workflow to be created + * @param actionableItems that were selected for the creation + * @return true if responsible, false if not + */ + public boolean isResponsibleForTeamWorkflowCreation(TeamDefinitionArtifact teamDef, Collection<ActionableItemArtifact> actionableItems) throws OseeCoreException; + + /** + * Same as @link getTeamWorkflowArtifactName() but returns the IArtifactType instead of String name. + */ + public IArtifactType getTeamWorkflowArtifactType(TeamDefinitionArtifact teamDef, Collection<ActionableItemArtifact> actionableItems) throws OseeCoreException; + + /** + * Notification that a teamWorkflow is being duplicated. This allows the extension to do necessary changes to + * duplicated workflow. + */ + public void teamWorkflowDuplicating(TeamWorkFlowArtifact teamArt, TeamWorkFlowArtifact dupTeamArt) throws OseeCoreException; + + /** + * Notification that a teamWorkflow was created. This allows the extension to do necessary initial tasks after the + * team workflow artifact is created. All changes made to dupTeamArt will be persisted after this call. + */ + public void teamWorkflowCreated(TeamWorkFlowArtifact teamArt); + + /** + * Return a collection of all team workflow artifact type names. These are used by ATS when searching is performed + * since there is no "inheritance" in the DB model. + * + * @return collection of all team workflow artifact type names + */ + public Collection<? extends IArtifactType> getTeamWorkflowArtifactTypes() throws OseeCoreException; + + public String getWorkflowDefinitionId(AbstractWorkflowArtifact artifact) throws OseeCoreException; + + public String getRelatedTaskWorkflowDefinitionId(AbstractWorkflowArtifact artifact) throws OseeCoreException; + + /** + * Assigned or computed Id that will show at the top of the editor + */ + public String getPcrId(TeamWorkFlowArtifact teamArt) throws OseeCoreException; + + /** + * 5-9 character short name for UI and display purposes + */ + public String getArtifactTypeShortName(TeamWorkFlowArtifact teamArt); + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteSMAStateUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteSMAStateUtil.java new file mode 100644 index 00000000000..00ffe8118f1 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteSMAStateUtil.java @@ -0,0 +1,59 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.util.WorkflowManagerCore; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class PercentCompleteSMAStateUtil { + + /** + * Return Percent Complete working ONLY the current state (not children SMAs) + */ + public static int getPercentCompleteSMAState(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + if (ActionManagerCore.getTeams(artifact).size() == 1) { + return getPercentCompleteSMAState(ActionManagerCore.getFirstTeam(artifact)); + } else { + double percent = 0; + int items = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + percent += getPercentCompleteSMAState(team); + items++; + } + } + if (items > 0) { + Double rollPercent = percent / items; + return rollPercent.intValue(); + } + } + return 0; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getPercentCompleteSMAState(artifact, WorkflowManagerCore.getStateManager(artifact).getCurrentState()); + } + return 0; + } + + /** + * Return Percent Complete working ONLY the SMA stateName (not children SMAs) + */ + public static int getPercentCompleteSMAState(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return WorkflowManagerCore.getStateManager(artifact).getPercentComplete(state); + } + return 0; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteTotalUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteTotalUtil.java new file mode 100644 index 00000000000..999741c1e2f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PercentCompleteTotalUtil.java @@ -0,0 +1,204 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import org.eclipse.osee.ats.core.review.AbstractReviewArtifact; +import org.eclipse.osee.ats.core.review.ReviewManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.task.TaskArtifact; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.WorkflowManagerCore; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class PercentCompleteTotalUtil { + + /** + * Return Percent Complete on all things (including children SMAs) for this SMA<br> + * <br> + * percent = all state's percents / number of states (minus completed/canceled) + */ + public static int getPercentCompleteTotal(Artifact artifact) throws OseeCoreException { + if (!(artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact))) { + return 0; + } + AbstractWorkflowArtifact awa = (AbstractWorkflowArtifact) artifact; + if (awa.isCompletedOrCancelled()) { + return 100; + } + if (awa.getWorkDefinition().isStateWeightingEnabled()) { + // Calculate total percent using configured weighting + int percent = 0; + for (StateDefinition stateDef : awa.getWorkDefinition().getStates()) { + if (!stateDef.isCompletedPage() && !stateDef.isCancelledPage()) { + double stateWeightInt = stateDef.getStateWeight(); + double weight = stateWeightInt / 100; + int percentCompleteForState = getPercentCompleteSMAStateTotal(awa, stateDef); + percent += weight * percentCompleteForState; + } + } + return percent; + } else { + int percent = getPercentCompleteSMASinglePercent(awa); + if (percent > 0) { + return percent; + } + if (awa.isCompletedOrCancelled()) { + return 100; + } + if (awa.getStateMgr().isAnyStateHavePercentEntered()) { + int numStates = 0; + for (StateDefinition state : awa.getWorkDefinition().getStates()) { + if (!state.isCompletedPage() && !state.isCancelledPage()) { + percent += getPercentCompleteSMAStateTotal(awa, state); + numStates++; + } + } + if (numStates == 0) { + return 0; + } + return percent / numStates; + } + + } + return 0; + } + + /** + * Add percent represented by percent attribute, percent for reviews and tasks divided by number of objects. + */ + private static int getPercentCompleteSMASinglePercent(Artifact artifact) throws OseeCoreException { + if (!(artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact))) { + return 0; + } + AbstractWorkflowArtifact awa = (AbstractWorkflowArtifact) artifact; + int numObjects = 1; + int percent = awa.getSoleAttributeValue(AtsAttributeTypes.PercentComplete, 0); + if (awa.isOfType(AtsArtifactTypes.TeamWorkflow)) { + for (AbstractReviewArtifact revArt : ReviewManager.getReviews((TeamWorkFlowArtifact) awa)) { + percent += getPercentCompleteTotal(revArt); + numObjects++; + } + } + if (awa instanceof AbstractTaskableArtifact) { + for (TaskArtifact taskArt : ((AbstractTaskableArtifact) awa).getTaskArtifacts()) { + percent += getPercentCompleteTotal(taskArt); + numObjects++; + } + } + if (percent > 0) { + if (numObjects == 0) { + return 0; + } + return percent / numObjects; + } + return percent; + } + + /** + * Return Percent Complete on all things (including children SMAs) related to stateName. Total Percent for state, + * tasks and reviews / 1 + # Tasks + # Reviews + */ + public static int getPercentCompleteSMAStateTotal(Artifact artifact, IWorkPage state) throws OseeCoreException { + return getStateMetricsData(artifact, state).getResultingPercent(); + } + + private static StateMetricsData getStateMetricsData(Artifact artifact, IWorkPage teamState) throws OseeCoreException { + if (!(artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact))) { + return null; + } + AbstractWorkflowArtifact awa = (AbstractWorkflowArtifact) artifact; + // Add percent and bump objects 1 for state percent + int percent = getPercentCompleteSMAState(awa, teamState); + int numObjects = 1; // the state itself is one object + + // Add percent for each task and bump objects for each task + if (awa instanceof AbstractTaskableArtifact) { + Collection<TaskArtifact> tasks = ((AbstractTaskableArtifact) awa).getTaskArtifacts(teamState); + for (TaskArtifact taskArt : tasks) { + percent += getPercentCompleteTotal(taskArt); + } + numObjects += tasks.size(); + } + + // Add percent for each review and bump objects for each review + if (awa.isOfType(AtsArtifactTypes.TeamWorkflow)) { + Collection<AbstractReviewArtifact> reviews = ReviewManager.getReviews((TeamWorkFlowArtifact) awa, teamState); + for (AbstractReviewArtifact reviewArt : reviews) { + percent += getPercentCompleteTotal(reviewArt); + } + numObjects += reviews.size(); + } + + return new StateMetricsData(percent, numObjects); + } + private static class StateMetricsData { + public int numObjects = 0; + public int percent = 0; + + public StateMetricsData(int percent, int numObjects) { + this.numObjects = numObjects; + this.percent = percent; + } + + public int getResultingPercent() { + return percent / numObjects; + } + + @Override + public String toString() { + return "Percent: " + getResultingPercent() + " NumObjs: " + numObjects + " Total Percent: " + percent; + } + } + + /** + * Return Percent Complete working ONLY the current state (not children SMAs) + */ + public static int getPercentCompleteSMAState(Artifact artifact) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.Action)) { + if (ActionManagerCore.getTeams(artifact).size() == 1) { + return getPercentCompleteSMAState(ActionManagerCore.getFirstTeam(artifact)); + } else { + double percent = 0; + int items = 0; + for (TeamWorkFlowArtifact team : ActionManagerCore.getTeams(artifact)) { + if (!team.isCancelled()) { + percent += getPercentCompleteSMAState(team); + items++; + } + } + if (items > 0) { + Double rollPercent = percent / items; + return rollPercent.intValue(); + } + } + return 0; + } + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return getPercentCompleteSMAState(artifact, WorkflowManagerCore.getStateManager(artifact).getCurrentState()); + } + return 0; + } + + /** + * Return Percent Complete working ONLY the SMA stateName (not children SMAs) + */ + public static int getPercentCompleteSMAState(Artifact artifact, IWorkPage state) throws OseeCoreException { + if (artifact.isOfType(AtsArtifactTypes.AbstractWorkflowArtifact)) { + return WorkflowManagerCore.getStateManager(artifact).getPercentComplete(state); + } + return 0; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PriorityUtil.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PriorityUtil.java new file mode 100644 index 00000000000..b8a82113eef --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/PriorityUtil.java @@ -0,0 +1,24 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +/** + * @author Donald G. Dunne + */ +public class PriorityUtil { + + public static String getPriorityStr(Object object) throws OseeCoreException { + if (object instanceof Artifact) { + return ((Artifact) object).getSoleAttributeValue(AtsAttributeTypes.PriorityType, ""); + } + return ""; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/SMAState.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/SMAState.java new file mode 100644 index 00000000000..b3f5677cc75 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/SMAState.java @@ -0,0 +1,217 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.HashSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.utility.UsersByIds; + +public class SMAState { + private String name; + private Collection<User> assignees = new HashSet<User>(); + private int percentComplete = 0; + private double hoursSpent = 0; + + @Override + public int hashCode() { + int result = 17; + result = result * 31 + name.hashCode(); + result = result * 31 + assignees.hashCode(); + + return result; + } + + public SMAState(String name, Collection<User> assignees) { + this.name = Strings.intern(name); + if (assignees != null) { + this.assignees = assignees; + } + } + + public SMAState(String name, User assignee) { + this.name = Strings.intern(name); + if (assignee != null) { + this.assignees.add(assignee); + } + } + + public SMAState(String name) { + this(name, (User) null); + } + + public SMAState() { + this("", (User) null); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SMAState) { + SMAState state = (SMAState) obj; + if (!state.name.equals(name)) { + return false; + } + if (!state.assignees.equals(this.assignees)) { + return false; + } + return true; + } + return super.equals(obj); + } + + public Collection<User> getAssignees() { + return assignees; + } + + /** + * Sets the assignees but DOES NOT write to SMA. This method should NOT be called outside the StateMachineArtifact. + */ + public void setAssignees(Collection<User> assignees) throws OseeCoreException { + if (assignees != null) { + if (assignees.contains(UserManager.getUser(SystemUser.OseeSystem)) || assignees.contains(UserManager.getUser(SystemUser.Guest))) { + throw new OseeArgumentException("Can not assign workflow to OseeSystem or Guest"); + } + if (assignees.size() > 1 && assignees.contains(UserManager.getUser(SystemUser.UnAssigned))) { + throw new OseeArgumentException("Can not assign to user and UnAssigned"); + } + if (assignees.size() > 0 && (name.equals(TeamState.Completed.getPageName()) || name.equals(TeamState.Cancelled.getPageName()))) { + throw new OseeStateException("Can't assign completed/cancelled states."); + } + } else { + assignees = new HashSet<User>(); + } + this.assignees.clear(); + this.assignees.addAll(assignees); + + } + + public void clearAssignees() { + this.assignees.clear(); + } + + /** + * Sets the assignees but DOES NOT write to SMA. This method should NOT be called outside the StateMachineArtifact. + */ + public void setAssignee(User assignee) throws OseeCoreException { + if (assignee != null && (name.equals(TeamState.Completed.getPageName()) || name.equals(TeamState.Cancelled.getPageName()))) { + throw new OseeStateException("Can't assign completed/cancelled states."); + } + if (assignee == UserManager.getUser(SystemUser.OseeSystem) || assignee == UserManager.getUser(SystemUser.Guest)) { + throw new OseeArgumentException("Can not assign workflow to OseeSystem or Guest"); + } + this.assignees.clear(); + if (assignee != null) { + this.assignees.add(assignee); + } + } + + public void addAssignee(User assignee) throws OseeCoreException { + if (assignee == UserManager.getUser(SystemUser.OseeSystem) || assignee == UserManager.getUser(SystemUser.Guest)) { + throw new OseeArgumentException("Can not assign workflow to OseeSystem or Guest"); + } + if (assignee != null) { + this.assignees.add(assignee); + } + } + + public void removeAssignee(User assignee) { + if (assignee != null) { + this.assignees.remove(assignee); + } + } + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + public String toXml() throws OseeCoreException { + StringBuffer sb = new StringBuffer(name); + sb.append(";"); + sb.append(UsersByIds.getStorageString(assignees)); + sb.append(";"); + if (hoursSpent > 0) { + sb.append(getHoursSpentStr()); + } + sb.append(";"); + if (percentComplete > 0) { + sb.append(percentComplete); + } + return sb.toString(); + } + + public static Pattern storagePattern = Pattern.compile("^(.*?);(.*?);(.*?);(.*?)$"); + + public void setFromXml(String xml) throws OseeCoreException { + if (!Strings.isValid(xml)) { + name = "Unknown"; + return; + } + Matcher m = storagePattern.matcher(xml); + if (m.find()) { + name = m.group(1); + if (!m.group(3).equals("")) { + hoursSpent = new Float(m.group(3)).doubleValue(); + } + if (!m.group(4).equals("")) { + percentComplete = Integer.valueOf(m.group(4)).intValue(); + } + assignees = UsersByIds.getUsers(m.group(2)); + } else { + throw new OseeArgumentException("Can't unpack state data [%s]", xml); + } + } + + public double getHoursSpent() { + return hoursSpent; + } + + public String getHoursSpentStr() { + return AtsUtilCore.doubleToI18nString(hoursSpent, true); + } + + public void setHoursSpent(double hoursSpent) { + this.hoursSpent = hoursSpent; + } + + public int getPercentComplete() { + return percentComplete; + } + + public void setPercentComplete(int percentComplete) { + this.percentComplete = percentComplete; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/StateManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/StateManager.java new file mode 100644 index 00000000000..95236b723e3 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/StateManager.java @@ -0,0 +1,448 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.team.SimpleTeamState; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workflow.log.LogItem; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; +import org.eclipse.osee.framework.skynet.core.artifact.search.ArtifactQuery; +import org.eclipse.osee.framework.skynet.core.utility.Artifacts; + +/** + * @author Donald G. Dunne + */ +public class StateManager { + + private final XCurrentStateDam currentStateDam; + private final XStateDam stateDam; + private final AbstractWorkflowArtifact sma; + private static final Set<String> notValidAttributeType = new HashSet<String>(); + + public StateManager(AbstractWorkflowArtifact sma) { + super(); + this.sma = sma; + currentStateDam = new XCurrentStateDam(sma); + stateDam = new XStateDam(sma); + } + + /** + * Get state and create if not there. + */ + private SMAState getSMAState(IWorkPage state, boolean create) throws OseeCoreException { + if (currentStateDam.getState().getName().equals(state.getPageName())) { + return currentStateDam.getState(); + } else { + return stateDam.getState(state, create); + } + } + + public boolean isAnyStateHavePercentEntered() throws OseeCoreException { + if (currentStateDam.getState().getPercentComplete() > 0) { + return true; + } + for (SMAState state : stateDam.getStates()) { + if (state.getPercentComplete() > 0) { + return true; + } + } + return false; + } + + public boolean isInState(IWorkPage state) { + return (getCurrentStateName().equals(state.getPageName())); + } + + /** + * Discouraged Access. This method should not normally be called except in cases were state data is being manually + * created. + */ + public void internalCreateIfNotExists(IWorkPage state) throws OseeCoreException { + if (isStateVisited(state)) { + return; + } + SMAState smaState = getSMAState(state, true); + putState(smaState); + } + + /** + * @return true if UnAssigned user is currently an assignee + */ + public boolean isUnAssigned() throws OseeCoreException { + return getAssignees().contains(UserManager.getUser(SystemUser.UnAssigned)); + } + + public boolean isUnAssignedSolely() throws OseeCoreException { + return getAssignees().size() == 1 && isUnAssigned(); + } + + /** + * Return Hours Spent for State + * + * @return hours spent or 0 if none + */ + public double getHoursSpent(IWorkPage state) throws OseeCoreException { + SMAState smaState = getSMAState(state, false); + if (smaState == null) { + return 0.0; + } + return smaState.getHoursSpent(); + } + + public double getHoursSpent() throws OseeCoreException { + return getHoursSpent(getCurrentState()); + } + + /** + * Return Percent Complete for State + * + * @return percent complete or 0 if none + */ + public int getPercentComplete(IWorkPage teamState) throws OseeCoreException { + if (teamState.getWorkPageType().isCompletedOrCancelledPage()) { + return 100; + } + SMAState state = getSMAState(teamState, false); + if (state == null) { + return 0; + } + return state.getPercentComplete(); + + } + + public int getPercentComplete() throws OseeCoreException { + return getPercentComplete(getCurrentState()); + } + + public String getCurrentStateName() { + try { + return currentStateDam.getState().getName(); + } catch (OseeCoreException ex) { + return ex.getLocalizedMessage(); + } + } + + public IWorkPage getCurrentState() { + return new SimpleTeamState(getCurrentStateName(), getCurrentWorkPageType()); + } + + public WorkPageType getCurrentWorkPageType() { + try { + if (sma.isAttributeTypeValid(AtsAttributeTypes.CurrentStateType)) { + // backward compatibility + if (sma.getSoleAttributeValueAsString(AtsAttributeTypes.CurrentStateType, null) == null) { + if (getCurrentStateName().equals(TeamState.Completed.getPageName())) { + return WorkPageType.Completed; + } else if (getCurrentStateName().equals(TeamState.Cancelled.getPageName())) { + return WorkPageType.Cancelled; + } else { + return WorkPageType.Working; + } + } else { + return WorkPageType.valueOf(sma.getSoleAttributeValueAsString(AtsAttributeTypes.CurrentStateType, null)); + } + } else { + // display console error, but only once + if (!notValidAttributeType.contains(sma.getArtifactTypeName())) { + notValidAttributeType.add(sma.getArtifactTypeName()); + System.err.println("CurrentStateType not valid for " + sma.getArtifactTypeName()); + } + // TODO get rid of this once database configured for new types (or leave for backward compatibility? + if (getCurrentStateName().equals(TeamState.Completed.getPageName())) { + return WorkPageType.Completed; + } else if (getCurrentStateName().equals(TeamState.Cancelled.getPageName())) { + return WorkPageType.Cancelled; + } else { + return WorkPageType.Working; + } + } + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return null; + } + + public String getAssigneesStr() throws OseeCoreException { + return Artifacts.toString("; ", sma.getStateMgr().getAssignees()); + } + + public String getAssigneesStr(int length) throws OseeCoreException { + String str = getAssigneesStr(); + if (str.length() > length) { + return str.substring(0, length - 1) + "..."; + } + return str; + } + + public Collection<User> getAssignees() throws OseeCoreException { + return getAssignees(getCurrentState()); + } + + public Collection<User> getAssignees(IWorkPage state) throws OseeCoreException { + SMAState smaState = getSMAState(state, false); + if (smaState == null) { + return Collections.emptyList(); + } else { + return smaState.getAssignees(); + } + } + + public void updateMetrics(double additionalHours, int percentComplete, boolean logMetrics) throws OseeCoreException { + updateMetrics(getCurrentState(), additionalHours, percentComplete, logMetrics); + } + + public void updateMetrics(IWorkPage state, double additionalHours, int percentComplete, boolean logMetrics) throws OseeCoreException { + if (sma.isInState(state)) { + currentStateDam.updateMetrics(additionalHours, percentComplete, logMetrics); + } else { + stateDam.updateMetrics(state, additionalHours, percentComplete, logMetrics); + } + } + + public void setMetrics(double hours, int percentComplete, boolean logMetrics, User user, Date date) throws OseeCoreException { + setMetrics(getCurrentState(), hours, percentComplete, logMetrics, user, date); + } + + public void setMetrics(IWorkPage state, double hours, int percentComplete, boolean logMetrics, User user, Date date) throws OseeCoreException { + if (state.getPageName().equals(getCurrentStateName())) { + currentStateDam.setMetrics(hours, percentComplete, logMetrics, user, date); + } else { + stateDam.setMetrics(state, hours, percentComplete, logMetrics, user, date); + } + } + + /** + * Sets the assignees as attributes and relations AND writes to SMA. Does not persist. + */ + public void setAssignees(Collection<User> assignees) throws OseeCoreException { + SMAState state = getSMAState(getCurrentState(), false); + state.setAssignees(assignees); + putState(state); + } + + /** + * Sets the assignee AND writes to SMA. Does not persist. + */ + public void setAssignee(IWorkPage state, User assignee) throws OseeCoreException { + if (!isStateVisited(state)) { + throw new OseeArgumentException("State [%s] does not exist.", state); + } + SMAState smaState = getSMAState(state, false); + smaState.setAssignee(assignee); + putState(smaState); + } + + /** + * Sets the assignee AND writes to SMA. Does not persist. + */ + public void setAssignee(User assignee) throws OseeCoreException { + SMAState smaState = getSMAState(getCurrentState(), false); + smaState.setAssignee(assignee); + putState(smaState); + } + + /** + * Removes the assignee from stateName state AND writes to SMA. Does not persist. + */ + public void removeAssignee(IWorkPage state, User assignee) throws OseeCoreException { + if (!isStateVisited(state)) { + return; + } + SMAState smaState = getSMAState(state, false); + smaState.removeAssignee(assignee); + putState(smaState); + } + + /** + * Removes the assignee AND writes to SMA. Does not persist. + */ + public void removeAssignee(User assignee) throws OseeCoreException { + SMAState smaState = getSMAState(getCurrentState(), false); + smaState.removeAssignee(assignee); + putState(smaState); + } + + /** + * Adds the assignee AND writes to SMA. Does not persist. Will remove UnAssigned user if another assignee exists. + */ + public void addAssignee(User assignee) throws OseeCoreException { + SMAState smaState = getSMAState(getCurrentState(), false); + smaState.addAssignee(assignee); + if (smaState.getAssignees().size() > 1 && smaState.getAssignees().contains( + UserManager.getUser(SystemUser.UnAssigned))) { + smaState.removeAssignee(UserManager.getUser(SystemUser.UnAssigned)); + } + putState(smaState); + } + + /** + * Removes ALL assignees AND writes to SMA. Does not persist. + */ + public void clearAssignees() throws OseeCoreException { + SMAState smaState = getSMAState(getCurrentState(), false); + smaState.clearAssignees(); + putState(smaState); + } + + public boolean isStateVisited(IWorkPage state) { + return getVisitedStateNames().contains(state.getPageName()); + } + + public void transitionHelper(Collection<User> toAssignees, StateDefinition fromState, StateDefinition toState, String cancelReason) throws OseeCoreException { + // Set XCurrentState info to XState + stateDam.setState(currentStateDam.getState()); + + // Set XCurrentState; If been to this state, copy state info from prev state; else create new + SMAState previousState = stateDam.getState(toState, false); + if (previousState == null) { + currentStateDam.setState(new SMAState(toState.getPageName(), toAssignees)); + } else { + if (!org.eclipse.osee.framework.jdk.core.util.Collections.isEqual(previousState.getAssignees(), toAssignees)) { + previousState.setAssignees(toAssignees); + } + currentStateDam.setState(previousState); + } + sma.setSoleAttributeValue(AtsAttributeTypes.CurrentStateType, toState.getWorkPageType().name()); + } + + /** + * Initializes state machine and sets the current state to stateName + */ + public void initializeStateMachine(IWorkPage state) throws OseeCoreException { + initializeStateMachine(state, null); + } + + /** + * Initializes state machine and sets the current state to stateName + */ + public void initializeStateMachine(IWorkPage state, Collection<User> assignees) throws OseeCoreException { + SMAState smaState = null; + if (getVisitedStateNames().contains(state.getPageName())) { + smaState = getSMAState(state, false); + } else { + if (assignees == null) { + smaState = new SMAState(state.getPageName(), UserManager.getUser()); + } else { + smaState = new SMAState(state.getPageName(), assignees); + } + } + currentStateDam.setState(smaState); + if (sma.isAttributeTypeValid(AtsAttributeTypes.CurrentStateType)) { + sma.setSoleAttributeValue(AtsAttributeTypes.CurrentStateType, state.getWorkPageType().name()); + } + } + + private void putState(SMAState state) throws OseeCoreException { + if (getCurrentStateName().equals(state.getName())) { + currentStateDam.setState(state); + } else { + stateDam.setState(state); + } + } + + public Collection<String> getVisitedStateNames() { + Set<String> names = new HashSet<String>(); + for (SMAState state : stateDam.getStates()) { + names.add(state.getName()); + } + names.add(getCurrentStateName()); + return names; + } + + public long getTimeInState() throws OseeCoreException { + return getTimeInState(getCurrentState()); + } + + public long getTimeInState(IWorkPage state) throws OseeCoreException { + if (state == null) { + return 0; + } + LogItem logItem = sma.getStateStartedData(state); + if (logItem == null) { + return 0; + } + return new Date().getTime() - logItem.getDate().getTime(); + } + + /** + * return currently assigned state machine artifacts + */ + public static Set<Artifact> getAssigned(User user) throws OseeCoreException { + return getAssigned(user, null); + } + + /** + * return currently assigned state machine artifacts that match clazz + * + * @param clazz to match or all if null + */ + public static Set<Artifact> getAssigned(User user, Class<?> clazz) throws OseeCoreException { + return getAssigned(user.getUserId(), clazz); + } + + /** + * return currently assigned state machine artifacts that match clazz + * + * @param clazz to match or all if null + */ + public static Set<Artifact> getAssigned(String userId, Class<?> clazz) throws OseeCoreException { + Set<Artifact> assigned = new HashSet<Artifact>(); + for (Artifact artifact : ArtifactQuery.getArtifactListFromAttribute(AtsAttributeTypes.CurrentState, + "%<" + userId + ">%", AtsUtilCore.getAtsBranch())) { + if (clazz == null || clazz.isInstance(artifact)) { + assigned.add(artifact); + } + } + return assigned; + + } + + public static Collection<User> getImplementersByState(AbstractWorkflowArtifact workflow, IWorkPage state) throws OseeCoreException { + Set<User> users = new HashSet<User>(); + if (workflow.isCancelled()) { + users.add(workflow.getCancelledBy()); + } else { + users.addAll(workflow.getStateMgr().getAssignees(state)); + User user = workflow.getCompletedBy(); + if (user != null) { + users.add(user); + } + } + return users; + } + + public void internalSetCurrentStateName(String stateName) throws OseeCoreException { + SMAState state = currentStateDam.getState(); + if (state != null && !state.getName().equals(stateName)) { + state.setName(stateName); + } + currentStateDam.setState(state); + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XCurrentStateDam.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XCurrentStateDam.java new file mode 100644 index 00000000000..cbdb6b95649 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XCurrentStateDam.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Date; +import java.util.Set; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.workflow.log.LogItem; +import org.eclipse.osee.ats.core.workflow.log.LogType; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; + +/** + * @author Donald G. Dunne + */ +public class XCurrentStateDam extends XStateAssigneesDam { + + public XCurrentStateDam(AbstractWorkflowArtifact awa) { + super(awa, AtsAttributeTypes.CurrentState); + } + + public SMAState getState() throws OseeCoreException { + Set<SMAState> states = getStates(); + if (states.size() != 1) { + throw new OseeArgumentException("Must be one current state. Found %d for %s", states.size(), awa.getGuid()); + } + return states.iterator().next(); + } + + @Override + public void setState(SMAState state) throws OseeCoreException { + awa.setSoleAttributeValue(attributeType, state.toXml()); + } + + public void updateMetrics(double additionalHours, int percentComplete, boolean logMetrics) throws OseeCoreException { + SMAState currState = getState(); + currState.setHoursSpent(currState.getHoursSpent() + additionalHours); + currState.setPercentComplete(percentComplete); + setState(currState); + if (logMetrics) { + logMetrics(awa.getStateMgr().getCurrentState(), UserManager.getUser(), new Date()); + } + } + + public void setMetrics(double hours, int percentComplete, boolean logMetrics, User user, Date date) throws OseeCoreException { + SMAState currState = getState(); + currState.setHoursSpent(hours); + currState.setPercentComplete(percentComplete); + setState(currState); + if (logMetrics) { + logMetrics(awa.getStateMgr().getCurrentState(), user, date); + } + } + + public static void logMetrics(AbstractWorkflowArtifact sma, String percent, String hours, IWorkPage state, User user, Date date) throws OseeCoreException { + LogItem logItem = + new LogItem(LogType.Metrics, date, user, state.getPageName(), String.format("Percent %s Hours %s", percent, + hours), sma.getHumanReadableId()); + sma.getLog().addLogItem(logItem); + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateAssigneesDam.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateAssigneesDam.java new file mode 100644 index 00000000000..9f98968f709 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateAssigneesDam.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.framework.core.data.IAttributeType; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.artifact.Attribute; + +/** + * @author Donald G. Dunne + */ +public abstract class XStateAssigneesDam { + + protected final IAttributeType attributeType; + protected final AbstractWorkflowArtifact awa; + + public XStateAssigneesDam(AbstractWorkflowArtifact awa, IAttributeType attributeType) { + this.awa = awa; + this.attributeType = attributeType; + } + + public SMAState getState(IWorkPage state, boolean create) { + try { + for (String stateXml : awa.getAttributesToStringList(attributeType)) { + if (stateXml.startsWith(state.getPageName() + ";")) { + SMAState smaState = new SMAState(); + smaState.setFromXml(stateXml); + return smaState; + } + } + if (create) { + return new SMAState(state.getPageName()); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, "Error parsing state data for " + awa.getGuid(), ex); + } + return null; + } + + public void updateMetrics(IWorkPage state, double additionalHours, int percentComplete, boolean logMetrics) throws OseeCoreException { + SMAState smaState = getState(state, false); + smaState.setHoursSpent(smaState.getHoursSpent() + additionalHours); + smaState.setPercentComplete(percentComplete); + setState(smaState); + if (logMetrics) { + logMetrics(state, UserManager.getUser(), new Date()); + } + } + + public void setMetrics(IWorkPage state, double hours, int percentComplete, boolean logMetrics, User user, Date date) throws OseeCoreException { + SMAState currState = getState(state, false); + currState.setHoursSpent(hours); + currState.setPercentComplete(percentComplete); + setState(currState); + if (logMetrics) { + logMetrics(state, user, date); + } + } + + protected void logMetrics(IWorkPage state, User user, Date date) throws OseeCoreException { + String hoursSpent = AtsUtilCore.doubleToI18nString(HoursSpentUtil.getHoursSpentTotal(awa)); + XCurrentStateDam.logMetrics(awa, PercentCompleteTotalUtil.getPercentCompleteTotal(awa) + "", hoursSpent, state, + user, date); + } + + public Set<SMAState> getStates() { + Set<SMAState> states = new HashSet<SMAState>(); + try { + for (String stateXml : awa.getAttributesToStringList(attributeType)) { + SMAState state = new SMAState(); + state.setFromXml(stateXml); + states.add(state); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, "Error parsing state data for " + awa.getGuid(), ex); + } + return states; + } + + @SuppressWarnings("unused") + public void setState(SMAState state) throws OseeCoreException { + // Update attribute if it already exists + try { + Collection<Attribute<String>> attrs = awa.getAttributes(attributeType); + for (Attribute<String> attr : attrs) { + SMAState storedState = new SMAState(); + storedState.setFromXml(attr.getValue()); + if (state.getName().equals(storedState.getName())) { + attr.setValue(state.toXml()); + return; + } + } + // Else, doesn't exist yet, create + awa.addAttribute(attributeType, state.toXml()); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, "Error setting state data for " + awa.getGuid(), ex); + } + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateDam.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateDam.java new file mode 100644 index 00000000000..4bfc7497392 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/XStateDam.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow; + +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; + +/** + * @author Donald G. Dunne + */ +public class XStateDam extends XStateAssigneesDam { + + public XStateDam(AbstractWorkflowArtifact sma) { + super(sma, AtsAttributeTypes.State); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ArtifactLog.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ArtifactLog.java new file mode 100644 index 00000000000..d3af7df5dbe --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ArtifactLog.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.log; + +import java.lang.ref.WeakReference; +import java.util.logging.Level; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +public class ArtifactLog implements ILogStorageProvider { + private final WeakReference<Artifact> artifactRef; + + public ArtifactLog(Artifact artifact) { + this.artifactRef = new WeakReference<Artifact>(artifact); + } + + @Override + public String getLogXml() { + try { + return getArtifact().getSoleAttributeValue(AtsAttributeTypes.Log, ""); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return "getLogXml exception " + ex.getLocalizedMessage(); + } + } + + @Override + public IStatus saveLogXml(String xml) { + try { + getArtifact().setSoleAttributeValue(AtsAttributeTypes.Log, xml); + return Status.OK_STATUS; + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "saveLogXml exception " + ex.getLocalizedMessage()); + } + } + + public Artifact getArtifact() throws OseeStateException { + if (artifactRef.get() == null) { + throw new OseeStateException("Artifact has been garbage collected"); + } + return artifactRef.get(); + } + + @Override + public String getLogTitle() { + try { + return "History for \"" + getArtifact().getArtifactTypeName() + "\" - " + getArtifact().getHumanReadableId() + " - titled \"" + getArtifact().getName() + "\""; + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return "getLogTitle exception " + ex.getLocalizedMessage(); + } + } + + @Override + public String getLogId() { + try { + return getArtifact().getHumanReadableId(); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return "unknown"; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/AtsLog.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/AtsLog.java new file mode 100644 index 00000000000..0ae36718521 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/AtsLog.java @@ -0,0 +1,390 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.workflow.log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.jdk.core.util.AHTML; +import org.eclipse.osee.framework.jdk.core.util.AXml; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.jdk.core.util.xml.Jaxp; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * @author Donald G. Dunne + */ +public class AtsLog { + + private boolean enabled = true; + private final static String ATS_LOG_TAG = "AtsLog"; + private final static String LOG_ITEM_TAG = "Item"; + private LogItem cancelledLogItem; + private LogItem completedLogItem; + private final ILogStorageProvider storeProvider; + private final static Pattern LOG_ITEM_PATTERN = + Pattern.compile("<Item date=\"(.*?)\" msg=\"(.*?)\" state=\"(.*?)\" type=\"(.*?)\" userId=\"(.*?)\"/>"); + private final static Pattern LOG_ITEM_TAG_PATTERN = Pattern.compile("<Item "); + + public AtsLog(ILogStorageProvider storeProvider) { + this.storeProvider = storeProvider; + } + + @Override + public String toString() { + try { + return org.eclipse.osee.framework.jdk.core.util.Collections.toString("\n", getLogItems()); + } catch (Exception ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return ex.getLocalizedMessage(); + } + } + + public String getHtml() throws OseeCoreException { + return getHtml(true); + } + + public String getHtml(boolean showLog) throws OseeCoreException { + if (getLogItems().isEmpty()) { + return ""; + } + StringBuffer sb = new StringBuffer(); + if (showLog) { + sb.append(AHTML.addSpace(1) + AHTML.getLabelStr(AHTML.LABEL_FONT, storeProvider.getLogTitle())); + } + sb.append(getTable()); + return sb.toString(); + } + + public List<LogItem> getLogItems() throws OseeCoreException { + String xml = storeProvider.getLogXml(); + return getLogItems(xml, storeProvider.getLogId()); + } + + private List<LogItem> getLogItems(String xml, String id) throws OseeCoreException { + List<LogItem> logItems = new ArrayList<LogItem>(); + if (!xml.isEmpty()) { + Matcher m = LOG_ITEM_PATTERN.matcher(xml); + while (m.find()) { + LogItem item = new LogItem(m.group(4), m.group(1), Strings.intern(m.group(5)), Strings.intern(m.group(3)), // NOPMD by b0727536 on 9/29/10 8:52 AM + AXml.xmlToText(m.group(2)), id); + logItems.add(item); + } + + Matcher m2 = LOG_ITEM_TAG_PATTERN.matcher(xml); + int openTagsFound = 0; + while (m2.find()) { + openTagsFound++; + } + if (logItems.size() != openTagsFound) { + OseeLog.log(Activator.class, Level.SEVERE, String.format( + "ATS Log: open tags found %d doesn't match log items parsed %d for %s", openTagsFound, logItems.size(), + id)); + } + } + return logItems; + } + + public Date getLastStatusedDate() throws OseeCoreException { + LogItem logItem = getLastEvent(LogType.Metrics); + if (logItem == null) { + return null; + } + return logItem.getDate(); + } + + public void putLogItems(List<LogItem> items) { + try { + Document doc = Jaxp.newDocumentNamespaceAware(); + Element rootElement = doc.createElement(ATS_LOG_TAG); + doc.appendChild(rootElement); + for (LogItem item : items) { + Element element = doc.createElement(LOG_ITEM_TAG); + element.setAttribute("type", item.getType().name()); + element.setAttribute("date", String.valueOf(item.getDate().getTime())); + element.setAttribute("userId", item.getUser().getUserId()); + element.setAttribute("state", item.getState()); + element.setAttribute("msg", item.getMsg()); + rootElement.appendChild(element); + } + storeProvider.saveLogXml(Jaxp.getDocumentXml(doc)); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't create ats log document", ex); + } + } + + public List<LogItem> getLogItemsReversed() throws OseeCoreException { + List<LogItem> logItems = getLogItems(); + Collections.reverse(logItems); + return logItems; + } + + /** + * Used to reset the original originated user. Only for internal use. Kept for backward compatibility. + */ + public void internalResetOriginator(User user) throws OseeCoreException { + List<LogItem> logItems = getLogItems(); + for (LogItem item : logItems) { + if (item.getType() == LogType.Originated) { + item.setUser(user); + putLogItems(logItems); + return; + } + } + } + + /** + * Used to reset the original originated user. Only for internal use. Kept for backward compatibility. + */ + public void internalResetCreatedDate(Date date) throws OseeCoreException { + List<LogItem> logItems = getLogItems(); + for (LogItem item : logItems) { + if (item.getType() == LogType.Originated) { + item.setDate(date); + putLogItems(logItems); + return; + } + } + } + + /** + * This method is replaced by AbstractWorkflowArtifact.getCancelledFromState. Kept for backward compatibility. + */ + public String internalGetCancelledFromState() throws OseeCoreException { + LogItem item = getStateEvent(LogType.StateCancelled); + if (item == null) { + return ""; + } + return item.getState(); + } + + public String internalGetCancelledReason() throws OseeCoreException { + LogItem item = getStateEvent(LogType.StateCancelled); + if (item == null) { + return ""; + } + return item.getMsg(); + } + + /** + * This method is replaced by AbstractWorkflowArtifact.getCompletedFromState. Kept for backward compatibility. + */ + public String internalGetCompletedFromState() throws OseeCoreException { + LogItem item = getStateEvent(LogType.StateComplete); + if (item == null) { + return ""; + } + return item.getState(); + } + + /** + * This method is replaced by AbstractWorkflowArtifact.setCompletedFromState. Kept for backward compatibility. + */ + public void internalSetCancellationReason(String reason) throws OseeCoreException { + List<LogItem> logItems = getLogItemsReversed(); + for (LogItem item : logItems) { + if (item.getType() == LogType.StateCancelled) { + item.setMsg(reason); + putLogItems(logItems); + return; + } + } + } + + /** + * Since originator can be changed, return the date of the first originated log item. Kept for backward + * compatibility. + */ + public Date internalGetCreationDate() throws OseeCoreException { + LogItem logItem = getEvent(LogType.Originated); + if (logItem == null) { + return null; + } + return logItem.getDate(); + } + + /** + * Since originator change be changed, return the last originated event's user. Kept for backward compatibility. + */ + public User internalGetOriginator() throws OseeCoreException { + LogItem logItem = getLastEvent(LogType.Originated); + if (logItem == null) { + return null; + } + return logItem.getUser(); + } + + /** + * Overwrite the first logItem to match type and state with newItem data + */ + public void overrideStateItemData(LogType matchType, String matchState, LogItem newItem) throws OseeCoreException { + List<LogItem> logItems = getLogItems(); + for (LogItem item : logItems) { + if (item.getType() == matchType && item.getState().equals(matchState)) { + item.setUser(newItem.getUser()); + item.setDate(newItem.getDate()); + item.setMsg(newItem.getMsg()); + item.setState(newItem.getState()); + putLogItems(logItems); + return; + } + } + } + + /** + * Overwrite the first logItem to match matchType with newItem data + */ + public void overrideItemData(LogType matchType, LogItem newItem) throws OseeCoreException { + List<LogItem> logItems = getLogItems(); + for (LogItem item : logItems) { + if (item.getType() == matchType) { + item.setState(newItem.getState()); + item.setUser(newItem.getUser()); + item.setDate(newItem.getDate()); + item.setMsg(newItem.getMsg()); + putLogItems(logItems); + return; + } + } + } + + /** + * @param state name of state or null + */ + public void addLog(LogType type, String state, String msg) throws OseeCoreException { + addLog(type, state, msg, new Date(), UserManager.getUser()); + } + + /** + * @param state name of state or null + */ + public void addLog(LogType type, String state, String msg, User user) throws OseeCoreException { + addLog(type, state, msg, new Date(), user); + } + + public void addLogItem(LogItem item) throws OseeCoreException { + addLog(item.getType(), item.getState(), item.getMsg(), item.getDate(), item.getUser()); + } + + public void addLog(LogType type, String state, String msg, Date date, User user) throws OseeCoreException { + if (!enabled) { + return; + } + LogItem logItem = new LogItem(type, date, user, state, msg, storeProvider.getLogId()); + List<LogItem> logItems = getLogItems(); + logItems.add(logItem); + putLogItems(logItems); + } + + public void clearLog() { + putLogItems(new ArrayList<LogItem>()); + } + + public String getTable() throws OseeCoreException { + StringBuilder builder = new StringBuilder(); + List<LogItem> logItems = getLogItems(); + builder.append(AHTML.beginMultiColumnTable(100, 1)); + builder.append(AHTML.addHeaderRowMultiColumnTable(Arrays.asList("Event", "State", "Message", "User", "Date"))); + for (LogItem item : logItems) { + User user = item.getUser(); + String userStr = null; + if (user == null) { + userStr = item.getUserId(); + } else { + userStr = user.getName(); + } + builder.append(AHTML.addRowMultiColumnTable(String.valueOf(item.getType()), + (item.getState().equals("") ? "." : item.getState()), (item.getMsg().equals("") ? "." : item.getMsg()), + userStr, item.getDate(DateUtil.MMDDYYHHMM))); + } + builder.append(AHTML.endMultiColumnTable()); + return builder.toString(); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public LogItem getEvent(LogType type) throws OseeCoreException { + for (LogItem item : getLogItems()) { + if (item.getType() == type) { + return item; + } + } + return null; + } + + public LogItem getLastEvent(LogType type) throws OseeCoreException { + for (LogItem item : getLogItemsReversed()) { + if (item.getType() == type) { + return item; + } + } + return null; + } + + public LogItem getStateEvent(LogType type, String stateName) throws OseeCoreException { + for (LogItem item : getLogItemsReversed()) { + if (item.getType() == type && item.getState().equals(stateName)) { + return item; + } + } + return null; + } + + public LogItem getStateEvent(LogType type) throws OseeCoreException { + for (LogItem item : getLogItemsReversed()) { + if (item.getType() == type) { + return item; + } + } + return null; + } + + /** + * This method is replaced by Cancelled Date, By and Reason attributes. It will not work with multiple cancelled + * state design + */ + public LogItem internalGetCancelledLogItem() throws OseeCoreException { + if (cancelledLogItem == null) { + cancelledLogItem = getStateEvent(LogType.StateEntered, "Cancelled"); + } + return cancelledLogItem; + } + + /** + * This method is replaced by Completed Date, By attributes. It will not work with multiple completed state design + */ + public LogItem internalGetCompletedLogItem() throws OseeCoreException { + if (completedLogItem == null) { + completedLogItem = getStateEvent(LogType.StateEntered, "Completed"); + } + return completedLogItem; + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ILogStorageProvider.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ILogStorageProvider.java new file mode 100644 index 00000000000..18e3e802ace --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/ILogStorageProvider.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.log; + +import org.eclipse.core.runtime.IStatus; + +public interface ILogStorageProvider { + + String getLogXml(); + + IStatus saveLogXml(String xml); + + String getLogTitle(); + + String getLogId(); +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogItem.java new file mode 100644 index 00000000000..7f2534c6d8e --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogItem.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.log; + +import static org.eclipse.osee.framework.jdk.core.util.Strings.intern; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.UserNotInDatabase; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; + +/** + * @author Donald G. Dunne + */ +public class LogItem { + + private Date date; + private String msg; + private String state; + private User user; + private LogType type = LogType.None; + private final String userId; + + public LogItem(LogType type, Date date, User user, String state, String msg, String hrid) throws OseeCoreException { + this(type.name(), String.valueOf(date.getTime()), user.getUserId(), state, msg, hrid); + } + + public LogItem(LogType type, String date, String userId, String state, String msg, String hrid) throws OseeCoreException { + Long dateLong = Long.valueOf(date); + this.date = new Date(dateLong.longValue()); + this.msg = msg; + this.state = intern(state); + this.userId = intern(userId); + try { + this.user = UserManager.getUserByUserId(userId); + } catch (UserNotInDatabase ex) { + this.user = UserManager.getUser(SystemUser.Guest); + OseeLog.log(Activator.class, Level.SEVERE, + String.format("Error parsing ATS Log for %s - %s", hrid, ex.getLocalizedMessage()), ex); + } + this.type = type; + } + + public LogItem(String type, String date, String userId, String state, String msg, String hrid) throws OseeCoreException { + this(LogType.getType(type), date, userId, state, msg, hrid); + } + + public Date getDate() { + return date; + } + + public String getDate(String pattern) { + if (pattern != null) { + return new SimpleDateFormat(pattern, Locale.US).format(date); + } + return date.toString(); + } + + public void setDate(Date date) { + this.date = date; + } + + public String getUserId() { + return userId; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + @Override + public String toString() { + return String.format("%s (%s)%s by %s on %s", getToStringMsg(), type, getToStringState(), getToStringUser(), + DateUtil.getMMDDYYHHMM(date)); + } + + private String getToStringUser() { + return user == null ? "unknown" : user.getName(); + } + + private String getToStringState() { + return state.isEmpty() ? "" : "from " + state; + } + + private String getToStringMsg() { + return msg.isEmpty() ? "" : msg; + } + + public User getUser() { + return user; + } + + public LogType getType() { + return type; + } + + public void setType(LogType type) { + this.type = type; + } + + public String toHTML(String labelFont) { + return "NOTE (" + type + "): " + msg + " (" + user.getName() + ")"; + } + + public void setUser(User user) { + this.user = user; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogType.java new file mode 100644 index 00000000000..f0216514bf5 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/log/LogType.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.log; + +import org.eclipse.osee.framework.core.exception.OseeArgumentException; + +public enum LogType { + None, + Assign, + Released, + Originated, + StateComplete, + StateCancelled, + StateEntered, + Error, + Note, + Metrics; + + public static LogType getType(String type) throws OseeArgumentException { + for (Enum<LogType> e : LogType.values()) { + if (e.name().equals(type)) { + return (LogType) e; + } + } + throw new OseeArgumentException("Unhandled LogType: [%s]", type); + } + +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/ArtifactNote.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/ArtifactNote.java new file mode 100644 index 00000000000..abdb2938300 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/ArtifactNote.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.note; + +import java.lang.ref.WeakReference; +import java.util.logging.Level; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.OseeStateException; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.artifact.Artifact; + +public class ArtifactNote implements INoteStorageProvider { + private final WeakReference<Artifact> artifactRef; + + public ArtifactNote(Artifact artifact) { + this.artifactRef = new WeakReference<Artifact>(artifact); + } + + @Override + public String getNoteXml() { + try { + return getArtifact().getSoleAttributeValue(AtsAttributeTypes.StateNotes, ""); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return "getLogXml exception " + ex.getLocalizedMessage(); + } + } + + @Override + public IStatus saveNoteXml(String xml) { + try { + getArtifact().setSoleAttributeValue(AtsAttributeTypes.StateNotes, xml); + return Status.OK_STATUS; + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "saveLogXml exception " + ex.getLocalizedMessage()); + } + } + + public Artifact getArtifact() throws OseeStateException { + if (artifactRef.get() == null) { + throw new OseeStateException("Artifact has been garbage collected"); + } + return artifactRef.get(); + } + + @Override + public String getNoteTitle() { + try { + return "History for \"" + getArtifact().getArtifactTypeName() + "\" - " + getArtifact().getHumanReadableId() + " - titled \"" + getArtifact().getName() + "\""; + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + return "getLogTitle exception " + ex.getLocalizedMessage(); + } + } + + @Override + public String getNoteId() { + try { + return getArtifact().getHumanReadableId(); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return "unknown"; + } + + @Override + public boolean isNoteable() { + try { + return getArtifact().isAttributeTypeValid(AtsAttributeTypes.StateNotes); + } catch (OseeCoreException ex) { + OseeLog.log(Activator.class, Level.SEVERE, ex); + } + return false; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/AtsNote.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/AtsNote.java new file mode 100644 index 00000000000..4875a0f4ce8 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/AtsNote.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.note; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.jdk.core.util.AHTML; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; + +/** + * @author Donald G. Dunne + */ +public class AtsNote { + private boolean enabled = true; + private final INoteStorageProvider storeProvder; + + public AtsNote(INoteStorageProvider storeProvder) { + this.storeProvder = storeProvder; + } + + public void addNote(NoteType type, String state, String msg, User user) { + addNote(type, state, msg, new Date(), user); + } + + public void addNoteItem(NoteItem noteItem) { + addNote(noteItem.getType(), noteItem.getState(), noteItem.getMsg(), noteItem.getDate(), noteItem.getUser()); + } + + public void addNote(NoteType type, String state, String msg, Date date, User user) { + if (!enabled) { + return; + } + NoteItem logItem = new NoteItem(type, state, String.valueOf(date.getTime()), user, msg); + List<NoteItem> logItems = getNoteItems(); + if (logItems.isEmpty()) { + logItems = Arrays.asList(logItem); + } else { + logItems.add(logItem); + } + saveNoteItems(logItems); + } + + public List<NoteItem> getNoteItems() { + try { + String xml = storeProvder.getNoteXml(); + if (Strings.isValid(xml)) { + return NoteItem.fromXml(xml, storeProvder.getNoteId()); + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + } + return Collections.emptyList(); + } + + public void saveNoteItems(List<NoteItem> items) { + try { + String xml = NoteItem.toXml(items); + storeProvder.saveNoteXml(xml); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't create ats note document", ex); + } + } + + /** + * Display Note Table; If state == null, only display non-state notes Otherwise, show only notes associated with + * state + */ + public String getTable(String state) { + if (!storeProvder.isNoteable()) { + return ""; + } + ArrayList<NoteItem> showNotes = new ArrayList<NoteItem>(); + List<NoteItem> noteItems = getNoteItems(); + + for (NoteItem li : noteItems) { + if (state == null && li.getState().equals("")) { + showNotes.add(li); + } else if (state != null && ("ALL".equals(state) || li.getState().equals(state))) { + showNotes.add(li); + } + } + if (showNotes.isEmpty()) { + return ""; + } + return buildTable(showNotes); + } + + private String buildTable(List<NoteItem> showNotes) { + StringBuilder builder = new StringBuilder(); + builder.append(AHTML.beginMultiColumnTable(100, 1)); + builder.append(AHTML.addHeaderRowMultiColumnTable(Arrays.asList("Type", "State", "Message", "User", "Date"))); + DateFormat dateFormat = getDateFormat(); + for (NoteItem note : showNotes) { + User user = note.getUser(); + String name = ""; + if (user != null) { + name = user.getName(); + if (!Strings.isValid(name)) { + name = user.getName(); + } + } + builder.append(AHTML.addRowMultiColumnTable(String.valueOf(note.getType()), + (note.getState().isEmpty() ? "," : note.getState()), (note.getMsg().equals("") ? "," : note.getMsg()), + name, dateFormat.format(note.getDate()))); + } + builder.append(AHTML.endMultiColumnTable()); + return builder.toString(); + } + + public DateFormat getDateFormat() { + return new SimpleDateFormat("MM/dd/yyyy h:mm a", Locale.US); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/INoteStorageProvider.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/INoteStorageProvider.java new file mode 100644 index 00000000000..3899ff51c2f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/INoteStorageProvider.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.note; + +import org.eclipse.core.runtime.IStatus; + +public interface INoteStorageProvider { + + String getNoteXml(); + + IStatus saveNoteXml(String xml); + + String getNoteTitle(); + + String getNoteId(); + + boolean isNoteable(); +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteItem.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteItem.java new file mode 100644 index 00000000000..14cf5207879 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteItem.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osee.ats.core.workflow.note; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.exception.UserNotInDatabase; +import org.eclipse.osee.framework.jdk.core.util.DateUtil; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.jdk.core.util.xml.Jaxp; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class NoteItem { + + private Date date; + private final String state; + private String msg; + private User user; + private NoteType type = NoteType.Other; + protected final static String LOG_ITEM_TAG = "Item"; + private final static String ATS_NOTE_TAG = "AtsNote"; + + public NoteItem(NoteType type, String state, String date, User user, String msg) { + Long l = Long.valueOf(date); + this.date = new Date(l.longValue()); + this.state = Strings.intern(state); + this.msg = msg; + this.user = user; + this.type = type; + } + + public NoteItem(String type, String state, String date, User user, String msg) throws OseeCoreException { + this(NoteType.getType(type), state, date, user, msg); + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + @Override + public String toString() { + return String.format("Note: %s from %s%s on %s - %s", type, user.getName(), toStringState(), + DateUtil.getMMDDYYHHMM(date), msg); + } + + private String toStringState() { + return (state.isEmpty() ? "" : " for \"" + state + "\""); + } + + public User getUser() { + return user; + } + + public NoteType getType() { + return type; + } + + public void setType(NoteType type) { + this.type = type; + } + + public String toHTML() { + return toString().replaceFirst("^Note: ", "<b>Note:</b>"); + } + + public String getState() { + return state; + } + + public void setUser(User user) { + this.user = user; + } + + public static List<NoteItem> fromXml(String xml, String hrid) { + List<NoteItem> logItems = new ArrayList<NoteItem>(); + try { + if (Strings.isValid(xml)) { + NodeList nodes = Jaxp.readXmlDocument(xml).getElementsByTagName(LOG_ITEM_TAG); + for (int i = 0; i < nodes.getLength(); i++) { + Element element = (Element) nodes.item(i); + try { + User user = UserManager.getUserByUserId(element.getAttribute("userId")); + NoteItem item = new NoteItem(element.getAttribute("type"), element.getAttribute("state"), // NOPMD by b0727536 on 9/29/10 8:52 AM + element.getAttribute("date"), user, element.getAttribute("msg")); + logItems.add(item); + } catch (UserNotInDatabase ex) { + OseeLog.log(Activator.class, Level.SEVERE, String.format("Error parsing notes for [%s]", hrid), ex); + NoteItem item = new NoteItem(element.getAttribute("type"), element.getAttribute("state"), // NOPMD by b0727536 on 9/29/10 8:52 AM + element.getAttribute("date"), UserManager.getUser(SystemUser.Guest), element.getAttribute("msg")); + logItems.add(item); + } + } + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + } + return logItems; + } + + public static String toXml(List<NoteItem> items) { + try { + Document doc = Jaxp.newDocumentNamespaceAware(); + Element rootElement = doc.createElement(ATS_NOTE_TAG); + doc.appendChild(rootElement); + for (NoteItem item : items) { + Element element = doc.createElement(NoteItem.LOG_ITEM_TAG); + element.setAttribute("type", item.getType().name()); + element.setAttribute("state", item.getState()); + element.setAttribute("date", String.valueOf(item.getDate().getTime())); + element.setAttribute("userId", item.getUser().getUserId()); + element.setAttribute("msg", item.getMsg()); + rootElement.appendChild(element); + } + return Jaxp.getDocumentXml(doc); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't create ats note document", ex); + } + return null; + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteType.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteType.java new file mode 100644 index 00000000000..813bd7e0d78 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/note/NoteType.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.note; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.osee.framework.core.exception.OseeArgumentException; + +/** + * @author Donald G. Dunne + */ +public enum NoteType { + Comment, + Question, + Error, + Other; + + public static NoteType getType(String type) throws OseeArgumentException { + for (NoteType e : NoteType.values()) { + if (e.name().equals(type)) { + return e; + } + } + throw new OseeArgumentException("Unhandled NoteType"); + } + + public static List<String> getNames() { + List<String> names = new ArrayList<String>(); + for (NoteType e : NoteType.values()) { + names.add(e.name()); + } + return names; + } + +}; diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/ITransitionListener.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/ITransitionListener.java new file mode 100644 index 00000000000..ce8b1aa92b7 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/ITransitionListener.java @@ -0,0 +1,28 @@ +/* + * Created on May 12, 2011 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow.transition; + +import java.util.Collection; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; + +/** + * @author Donald G. Dunne + */ +public interface ITransitionListener { + + /** + * @return Result of operation. If Result.isFalse(), transition will not continue and Result.popup will occur. + */ + public Result transitioning(AbstractWorkflowArtifact sma, IWorkPage fromState, IWorkPage toState, Collection<User> toAssignees) throws OseeCoreException; + + public void transitioned(AbstractWorkflowArtifact sma, IWorkPage fromState, IWorkPage toState, Collection<User> toAssignees, SkynetTransaction transaction) throws OseeCoreException; + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionListeners.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionListeners.java new file mode 100644 index 00000000000..3894c051d22 --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionListeners.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.transition; + +import java.util.HashSet; +import java.util.Set; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.osgi.framework.Bundle; + +/** + * @author Donald G. Dunne + */ +public final class TransitionListeners { + + private static Set<ITransitionListener> listeners; + + private TransitionListeners() { + // private constructor + } + + /* + * due to lazy initialization, this function is non-reentrant therefore, the synchronized keyword is necessary + */ + private synchronized static Set<ITransitionListener> ensureLoaded() { + if (listeners != null) { + return listeners; + } + listeners = new HashSet<ITransitionListener>(); + + IExtensionPoint point = + Platform.getExtensionRegistry().getExtensionPoint("org.eclipse.osee.ats.core.AtsTransitionListener"); + if (point == null) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Can't access AtsTransitionListener extension point"); + return listeners; + } + IExtension[] extensions = point.getExtensions(); + for (IExtension extension : extensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + String classname = null; + String bundleName = null; + for (IConfigurationElement el : elements) { + if (el.getName().equals("AtsTransitionListener")) { + classname = el.getAttribute("classname"); + bundleName = el.getContributor().getName(); + if (classname != null && bundleName != null) { + Bundle bundle = Platform.getBundle(bundleName); + try { + Class<?> taskClass = bundle.loadClass(classname); + Object obj = taskClass.newInstance(); + listeners.add((ITransitionListener) obj); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, + "Error loading AtsTransitionListener extension", ex); + } + } + } + } + } + return listeners; + } + + public static Set<ITransitionListener> getListeners() { + ensureLoaded(); + return listeners; + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionManager.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionManager.java new file mode 100644 index 00000000000..6f266ac0c8f --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionManager.java @@ -0,0 +1,495 @@ +/* + * Created on Nov 17, 2010 + * + * PLACE_YOUR_DISTRIBUTION_STATEMENT_RIGHT_HERE + */ +package org.eclipse.osee.ats.core.workflow.transition; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.logging.Level; +import org.eclipse.osee.ats.core.branch.AtsBranchManagerCore; +import org.eclipse.osee.ats.core.internal.Activator; +import org.eclipse.osee.ats.core.review.AbstractReviewArtifact; +import org.eclipse.osee.ats.core.review.ReviewManager; +import org.eclipse.osee.ats.core.task.AbstractTaskableArtifact; +import org.eclipse.osee.ats.core.task.TaskArtifact; +import org.eclipse.osee.ats.core.team.TeamState; +import org.eclipse.osee.ats.core.team.TeamWorkFlowArtifact; +import org.eclipse.osee.ats.core.type.ATSAttributes; +import org.eclipse.osee.ats.core.type.AtsArtifactTypes; +import org.eclipse.osee.ats.core.type.AtsAttributeTypes; +import org.eclipse.osee.ats.core.util.AtsUtilCore; +import org.eclipse.osee.ats.core.util.WorkflowManagerCore; +import org.eclipse.osee.ats.core.workdef.ReviewBlockType; +import org.eclipse.osee.ats.core.workdef.RuleDefinitionOption; +import org.eclipse.osee.ats.core.workdef.StateDefinition; +import org.eclipse.osee.ats.core.workdef.WidgetDefinition; +import org.eclipse.osee.ats.core.workdef.WidgetOption; +import org.eclipse.osee.ats.core.workflow.AbstractWorkflowArtifact; +import org.eclipse.osee.ats.core.workflow.log.LogType; +import org.eclipse.osee.framework.core.data.SystemUser; +import org.eclipse.osee.framework.core.exception.OseeCoreException; +import org.eclipse.osee.framework.core.util.IWorkPage; +import org.eclipse.osee.framework.core.util.Result; +import org.eclipse.osee.framework.core.util.WorkPageType; +import org.eclipse.osee.framework.jdk.core.util.Strings; +import org.eclipse.osee.framework.logging.OseeLevel; +import org.eclipse.osee.framework.logging.OseeLog; +import org.eclipse.osee.framework.skynet.core.User; +import org.eclipse.osee.framework.skynet.core.UserManager; +import org.eclipse.osee.framework.skynet.core.attribute.AttributeTypeManager; +import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; +import org.eclipse.osee.framework.skynet.core.validation.OseeXWidgetValidateManager; + +public class TransitionManager { + + private final AbstractWorkflowArtifact awa; + private StateDefinition toStateDefinition; + private final boolean priviledgedEditEnabled; + private String cancellationReason; + + public TransitionManager(AbstractWorkflowArtifact awa) { + this(awa, false); + } + + public TransitionManager(AbstractWorkflowArtifact awa, boolean priviledgedEditEnabled) { + this.awa = awa; + this.priviledgedEditEnabled = priviledgedEditEnabled; + } + + public Result handleTransition(StateDefinition toStateDefinition, String cancellationReason) { + this.toStateDefinition = toStateDefinition; + this.cancellationReason = cancellationReason; + try { + + if (!WorkflowManagerCore.isEditable(awa, awa.getStateDefinition(), priviledgedEditEnabled) && !awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.UnAssigned))) { + return new Result( + "You must be assigned to transition this workflow.\nContact Assignee or Select Priviledged Edit for Authorized Overriders."); + } + + Result result = isWorkingBranchTransitionable(); + if (result.isFalse()) { + return result; + } + + if (toStateDefinition == null) { + return new Result("No Transition State Selected"); + } + if (toStateDefinition.isCancelledPage()) { + return handleTransitionToCancelled(awa); + } + + // Validate assignees + if (awa.getStateMgr().getAssignees().contains(UserManager.getUser(SystemUser.OseeSystem)) || awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.Guest)) || awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.UnAssigned))) { + return new Result("Can not transition with \"Guest\", \"UnAssigned\" or \"OseeSystem\" user as assignee."); + } + + awa.setInTransition(true); + + // As a convenience, if assignee is UnAssigned and user selects to transition, make user current assignee + if (awa.getStateMgr().getAssignees().contains(UserManager.getUser(SystemUser.UnAssigned))) { + awa.getStateMgr().removeAssignee(UserManager.getUser(SystemUser.UnAssigned)); + awa.getStateMgr().addAssignee(UserManager.getUser()); + } + + // Get transition to assignees + Collection<User> toAssignees; + if (toStateDefinition.isCancelledPage() || toStateDefinition.isCompletedPage()) { + toAssignees = new HashSet<User>(); + } else { + toAssignees = awa.getTransitionAssignees(); + if (toAssignees.isEmpty()) { + toAssignees.add(UserManager.getUser()); + } + } + + // If overrideAttributeValidation state, don't require page/tasks to be complete + boolean isOverrideAttributeValidationState = + awa.getStateDefinition().getOverrideAttributeValidationStates().contains(toStateDefinition); + if (!isOverrideAttributeValidationState) { + result = isStateTransitionable(awa.getStateDefinition(), toStateDefinition, toAssignees); + if (result.isFalse()) { + return result; + } + } + + // Persist must be done prior and separate from transition + awa.persist(); + + // Perform transition separate from persist of previous changes to state machine artifact + SkynetTransaction transaction = new SkynetTransaction(AtsUtilCore.getAtsBranch(), "ATS Transition"); + result = transition(toStateDefinition, toAssignees, transaction, TransitionOption.Persist); + transaction.execute(); + if (result.isFalse()) { + return result; + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + } finally { + awa.setInTransition(false); + } + return Result.TrueResult; + } + + private Result isWorkingBranchTransitionable() throws OseeCoreException { + if (awa.isTeamWorkflow() && AtsBranchManagerCore.isWorkingBranchInWork(((TeamWorkFlowArtifact) awa))) { + + if (toStateDefinition.getPageName().equals(TeamState.Cancelled.getPageName())) { + new Result("Working Branch exists.\n\nPlease delete working branch before transition to cancel."); + } + if (AtsBranchManagerCore.isBranchInCommit(((TeamWorkFlowArtifact) awa))) { + new Result("Working Branch is being Committed.\n\nPlease wait till commit completes to transition."); + } + if (!isAllowTransitionWithWorkingBranch(toStateDefinition)) { + new Result("Working Branch exists.\n\nPlease commit or delete working branch before transition."); + } + } + return Result.TrueResult; + } + + public static boolean isAllowTransitionWithWorkingBranch(StateDefinition stateDefinition) { + return stateDefinition.hasRule(RuleDefinitionOption.AllowTransitionWithWorkingBranch); + } + + /** + * Return collection of problems with state widgets and artifact model storage + */ + private Collection<ValidResult> isStateValid(AbstractWorkflowArtifact awa, StateDefinition stateDef) throws OseeCoreException { + List<ValidResult> results = new ArrayList<ValidResult>(); + for (WidgetDefinition widgetDef : stateDef.getWidgets()) { + ValidResult result = isWidgetValid(awa, widgetDef); + if (result != null) { + results.add(result); + } + } + return results; + } + + private static enum ValidType { + RequiredForCompletion, + RequiredForTransition; + } + + private static class ValidResult { + public ValidType type; + public WidgetDefinition widgetDef; + + public ValidResult(ValidType type, WidgetDefinition widgetDef) { + super(); + this.type = type; + this.widgetDef = widgetDef; + } + } + + /** + * Return result of validity between widget and artifact model storage + */ + public static ValidResult isWidgetValid(AbstractWorkflowArtifact awa, WidgetDefinition widgetDef) throws OseeCoreException { + // validate first with providers of validation + if (Strings.isValid(widgetDef.getXWidgetName())) { + OseeXWidgetValidateManager.instance.validate(awa, widgetDef.getXWidgetName(), widgetDef.getName()); + } + + // else fallback on attribute validation if this is an artifact stored widget + if (Strings.isValid(widgetDef.getAtrributeName())) { + if (widgetDef.getOptions().contains(WidgetOption.REQUIRED_FOR_COMPLETION)) { + if (awa.getAttributesToStringList(AttributeTypeManager.getType(widgetDef.getAtrributeName())).isEmpty()) { + return new ValidResult(ValidType.RequiredForCompletion, widgetDef); + } + } else if (widgetDef.getOptions().contains(WidgetOption.REQUIRED_FOR_TRANSITION)) { + if (awa.getAttributesToStringList(AttributeTypeManager.getType(widgetDef.getAtrributeName())).isEmpty()) { + return new ValidResult(ValidType.RequiredForTransition, widgetDef); + } + } + } + return null; + } + + private Result isStateTransitionable(StateDefinition fromStateDefinition, StateDefinition toStateDefinition, Collection<User> toAssignees) throws OseeCoreException { + // Validate XWidgets for transition + Collection<ValidResult> stateValid = isStateValid(awa, fromStateDefinition); + StringBuffer sb = new StringBuffer(); + for (ValidResult validResult : stateValid) { + // Stop transition if any errors exist + if (validResult.type == ValidType.RequiredForTransition) { + sb.append(String.format("[%s] required for transition\n", validResult.widgetDef.getName())); + } + // Only stop transition on warning if transitioning to completed state and REQUIRED_FOR_COMPLETION + else if (validResult.type == ValidType.RequiredForCompletion) { + boolean reqForCompletion = + validResult.widgetDef.getOptions().contains(WidgetOption.REQUIRED_FOR_COMPLETION); + if (reqForCompletion && toStateDefinition.getWorkPageType() == WorkPageType.Completed) { + sb.append(String.format("[%s] required for completion\n", validResult.widgetDef.getName())); + } + } + } + if (!sb.toString().isEmpty()) { + return new Result(sb.toString()); + } + + // Loop through this state's tasks to confirm complete + if (awa instanceof AbstractTaskableArtifact && !awa.isCompletedOrCancelled()) { + for (TaskArtifact taskArt : ((AbstractTaskableArtifact) awa).getTaskArtifactsFromCurrentState()) { + if (taskArt.isInWork()) { + return new Result( + "Transition Blocked: Task Not Complete\n\nTitle: " + taskArt.getName() + "\n\nHRID: " + taskArt.getHumanReadableId()); + } + } + } + + // Don't transition without targeted version if so configured + boolean teamDefRequiresTargetedVersion = awa.teamDefHasRule(RuleDefinitionOption.RequireTargetedVersion); + boolean pageRequiresTargetedVersion = + awa.getStateDefinition().hasRule(RuleDefinitionOption.RequireTargetedVersion); + + // Only check this if TeamWorkflow, not for reviews + if (awa.isOfType(AtsArtifactTypes.TeamWorkflow) && (teamDefRequiresTargetedVersion || pageRequiresTargetedVersion) && // + awa.getTargetedVersion() == null && // + !toStateDefinition.isCancelledPage()) { + return new Result( + "Transition Blocked: Actions must be targeted for a Version.\nPlease set \"Target Version\" before transition."); + } + + // Loop through this state's blocking reviews to confirm complete + if (awa.isTeamWorkflow()) { + for (AbstractReviewArtifact reviewArt : ReviewManager.getReviewsFromCurrentState((TeamWorkFlowArtifact) awa)) { + if (reviewArt.getReviewBlockType() == ReviewBlockType.Transition && !reviewArt.isCompletedOrCancelled()) { + return new Result("Transition Blocked: All Blocking Reviews must be completed before transition."); + } + } + } + + // Check extension points for valid transition + for (ITransitionListener listener : TransitionListeners.getListeners()) { + try { + Result result = + listener.transitioning(awa, awa.getStateMgr().getCurrentState(), toStateDefinition, toAssignees); + if (result.isFalse()) { + return result; + } + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, "Exception occurred during transition; Aborting.", ex); + return new Result(String.format("Exception occurred during transition; Aborting. [%s]", + ex.getLocalizedMessage())); + } + } + + return Result.TrueResult; + } + + private Result handleTransitionToCancelled(AbstractWorkflowArtifact awa) throws OseeCoreException { + SkynetTransaction transaction = new SkynetTransaction(AtsUtilCore.getAtsBranch(), "ATS Transition to Cancelled"); + TransitionManager transitionMgr = new TransitionManager(awa); + Result result = transitionMgr.transitionToCancelled(cancellationReason, transaction, TransitionOption.Persist); + if (result.isFalse()) { + return result; + } + awa.setInTransition(false); + transaction.execute(); + return Result.TrueResult; + } + + public Result isTransitionValid(final IWorkPage toState, final Collection<User> toAssignees, TransitionOption... transitionOption) throws OseeCoreException { + boolean overrideTransitionCheck = + org.eclipse.osee.framework.jdk.core.util.Collections.getAggregate(transitionOption).contains( + TransitionOption.OverrideTransitionValidityCheck); + boolean overrideAssigneeCheck = + org.eclipse.osee.framework.jdk.core.util.Collections.getAggregate(transitionOption).contains( + TransitionOption.OverrideAssigneeCheck); + // Validate assignees + if (!overrideAssigneeCheck && (awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.OseeSystem)) || awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.Guest)) || awa.getStateMgr().getAssignees().contains( + UserManager.getUser(SystemUser.UnAssigned)))) { + return new Result("Can not transition with \"Guest\", \"UnAssigned\" or \"OseeSystem\" user as assignee."); + } + + // Validate toState name + final StateDefinition fromStateDefinition = awa.getStateDefinition(); + final StateDefinition toStateDefinition = awa.getStateDefinitionByName(toState.getPageName()); + if (toStateDefinition == null) { + return new Result(String.format("Transition-To State [%s] does not exist for Work Definition [%s]", + toState.getPageName(), awa.getWorkDefinition().getName())); + } + + // Validate transition from fromPage to toPage + if (!overrideTransitionCheck && !fromStateDefinition.getToStates().contains(toStateDefinition) && !fromStateDefinition.isCompletedOrCancelledPage()) { + String errStr = + String.format("Work Definition [%s] is not configured to transition from \"[%s]\" to \"[%s]\"", + toStateDefinition.getName(), fromStateDefinition.getPageName(), toState.getPageName()); + OseeLog.log(Activator.class, Level.SEVERE, errStr); + return new Result(errStr); + } + // Don't transition with existing working branch + if (toStateDefinition.isCancelledPage() && awa.isTeamWorkflow() && AtsBranchManagerCore.isWorkingBranchInWork(((TeamWorkFlowArtifact) awa))) { + return new Result("Working Branch exists. Please delete working branch before cancelling."); + } + + // Don't transition with uncommitted branch if this is a commit state + if (isAllowCommitBranch(awa.getStateDefinition()) && awa.isTeamWorkflow() && AtsBranchManagerCore.isWorkingBranchInWork(((TeamWorkFlowArtifact) awa))) { + return new Result("Working Branch exists. Please commit or delete working branch before transition."); + } + + // Check extension points for valid transition + for (ITransitionListener listener : TransitionListeners.getListeners()) { + Result result = listener.transitioning(awa, fromStateDefinition, toState, toAssignees); + if (result.isFalse()) { + return result; + } + } + // Check again in case first check made changes that would now keep transition from happening + for (ITransitionListener listener : TransitionListeners.getListeners()) { + Result result = listener.transitioning(awa, fromStateDefinition, toState, toAssignees); + if (result.isFalse()) { + return result; + } + } + return Result.TrueResult; + } + + public static boolean isAllowCommitBranch(StateDefinition stateDefinition) { + return stateDefinition.hasRule(ATSAttributes.COMMIT_MANAGER_WIDGET.getWorkItemId()); + } + + public Result transition(IWorkPage toState, User toAssignee, SkynetTransaction transaction, TransitionOption... transitionOption) { + List<User> users = new ArrayList<User>(); + if (toAssignee != null && !toState.getWorkPageType().isCompletedOrCancelledPage()) { + users.add(toAssignee); + } + return transition(toState, users, transaction, transitionOption); + } + + public Result transition(IWorkPage toState, Collection<User> toAssignees, SkynetTransaction transaction, TransitionOption... transitionOption) { + return transition(toState, toAssignees, (String) null, transaction, transitionOption); + } + + private Result transition(final IWorkPage toState, final Collection<User> toAssignees, final String completeOrCancelReason, SkynetTransaction transaction, TransitionOption... transitionOption) { + try { + final boolean persist = + org.eclipse.osee.framework.jdk.core.util.Collections.getAggregate(transitionOption).contains( + TransitionOption.Persist); + + Result result = isTransitionValid(toState, toAssignees, transitionOption); + if (result.isFalse()) { + return result; + } + + final StateDefinition fromStateDefinition = awa.getStateDefinition(); + final StateDefinition toStateDefinition = awa.getStateDefinitionByName(toState.getPageName()); + + transitionHelper(toAssignees, persist, fromStateDefinition, toStateDefinition, completeOrCancelReason, + transaction); + } catch (Exception ex) { + OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex); + return new Result("Transaction failed " + ex.getLocalizedMessage()); + } + return Result.TrueResult; + } + + private void transitionHelper(Collection<User> toAssignees, boolean persist, StateDefinition fromState, StateDefinition toState, String completeOrCancelReason, SkynetTransaction transaction) throws OseeCoreException { + Date transitionDate = new Date(); + User transitionUser = UserManager.getUser(); + // Log transition + if (toState.isCancelledPage()) { + logWorkflowCancelledEvent(awa.getStateMgr().getCurrentStateName(), completeOrCancelReason, transitionDate, + transitionUser); + } else if (toState.isCompletedPage()) { + logWorkflowCompletedEvent(awa.getStateMgr().getCurrentStateName(), completeOrCancelReason, transitionDate, + transitionUser); + } else { + logStateCompletedEvent(awa.getStateMgr().getCurrentStateName(), completeOrCancelReason, transitionDate, + transitionUser); + } + if (fromState.isCancelledPage()) { + logWorkflowUnCancelledEvent(); + } else if (fromState.isCompletedPage()) { + logWorkflowUnCompletedEvent(); + } + logStateStartedEvent(toState, transitionDate, transitionUser); + + awa.getStateMgr().transitionHelper(toAssignees, fromState, toState, completeOrCancelReason); + + if (awa.isValidationRequired() && awa.isTeamWorkflow()) { + ReviewManager.createValidateReview((TeamWorkFlowArtifact) awa, false, transitionDate, transitionUser, + transaction); + } + + // Persist + if (persist) { + awa.persist(transaction); + } + + awa.transitioned(fromState, toState, toAssignees, true, transaction); + + // Notify extension points of transition + for (ITransitionListener listener : TransitionListeners.getListeners()) { + listener.transitioned(awa, fromState, toState, toAssignees, transaction); + } + } + + public Result transitionToCancelled(String reason, SkynetTransaction transaction, TransitionOption... transitionOption) { + Result result = + transition(TeamState.Cancelled, Arrays.asList(new User[] {}), reason, transaction, transitionOption); + return result; + } + + public Result transitionToCompleted(String reason, SkynetTransaction transaction, TransitionOption... transitionOption) { + Result result = + transition(TeamState.Completed, Arrays.asList(new User[] {}), reason, transaction, transitionOption); + return result; + } + + public void logWorkflowCancelledEvent(String fromStateName, String reason, Date cancelDate, User cancelBy) throws OseeCoreException { + awa.getLog().addLog(LogType.StateCancelled, fromStateName, reason, cancelDate, cancelBy); + if (awa.isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + awa.setSoleAttributeValue(AtsAttributeTypes.CancelledBy, cancelBy.getUserId()); + awa.setSoleAttributeValue(AtsAttributeTypes.CancelledDate, cancelDate); + awa.setSoleAttributeValue(AtsAttributeTypes.CancelledReason, reason); + awa.setSoleAttributeValue(AtsAttributeTypes.CancelledFromState, fromStateName); + } + } + + public void logWorkflowUnCancelledEvent() throws OseeCoreException { + if (awa.isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + awa.deleteSoleAttribute(AtsAttributeTypes.CancelledBy); + awa.deleteSoleAttribute(AtsAttributeTypes.CancelledDate); + awa.deleteSoleAttribute(AtsAttributeTypes.CancelledReason); + awa.deleteSoleAttribute(AtsAttributeTypes.CancelledFromState); + } + } + + public void logWorkflowCompletedEvent(String fromStateName, String reason, Date cancelDate, User cancelBy) throws OseeCoreException { + awa.getLog().addLog(LogType.StateComplete, fromStateName, Strings.isValid(reason) ? reason : "", cancelDate, + cancelBy); + if (awa.isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + awa.setSoleAttributeValue(AtsAttributeTypes.CompletedBy, cancelBy.getUserId()); + awa.setSoleAttributeValue(AtsAttributeTypes.CompletedDate, cancelDate); + awa.setSoleAttributeValue(AtsAttributeTypes.CompletedFromState, fromStateName); + } + } + + public void logWorkflowUnCompletedEvent() throws OseeCoreException { + if (awa.isAttributeTypeValid(AtsAttributeTypes.CreatedBy)) { + awa.deleteSoleAttribute(AtsAttributeTypes.CompletedBy); + awa.deleteSoleAttribute(AtsAttributeTypes.CompletedDate); + awa.deleteSoleAttribute(AtsAttributeTypes.CompletedFromState); + } + } + + public void logStateCompletedEvent(String fromStateName, String reason, Date date, User user) throws OseeCoreException { + awa.getLog().addLog(LogType.StateComplete, fromStateName, Strings.isValid(reason) ? reason : ""); + } + + public void logStateStartedEvent(IWorkPage state, Date date, User user) throws OseeCoreException { + awa.getLog().addLog(LogType.StateEntered, state.getPageName(), ""); + } + +} diff --git a/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionOption.java b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionOption.java new file mode 100644 index 00000000000..afa03b678fa --- /dev/null +++ b/plugins/org.eclipse.osee.ats.core/src/org/eclipse/osee/ats/core/workflow/transition/TransitionOption.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2010 Boeing. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Boeing - initial API and implementation + *******************************************************************************/ +package org.eclipse.osee.ats.core.workflow.transition; + +public enum TransitionOption { + None, + Persist, + // Override check whether workflow allows transition to state + OverrideTransitionValidityCheck, + // Allows transition to occur with UnAssigned, OseeSystem or Guest + OverrideAssigneeCheck +}; |