Rev 2161 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
using System;using System.Text;using System.Globalization;using System.Collections;using System.Windows.Forms;using ReqPro40;namespace EA_ReqPro{/// <summary>/// ExportToReqProDatabase is a specialisation of CopyReqProDatabaseToMemory, designed to copy the/// ReqPro database content into memory, and allow a user to select certain aspects to control a/// subsequent export operation./// </summary>public class ExportToReqProDatabase : CopyReqProDatabaseToMemory{private ReqPro_object m_SelectedObject;private bool m_CreateFolder;private string m_FolderName;private string m_ReqType;private ExportForm.ExportExtent m_ExportExtent;private static char [] numbers = "0123456789".ToCharArray();private static char [] letters = "abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY".ToCharArray();public ExportToReqProDatabase(){}/// <summary>/// Method to parse a ReqPro database using the information in a ReqProDB artifact,/// assumed to be selected in EA's project browser prior to the method call./// </summary>/// <param name="ea_repository"></param>/// <returns></returns>public override bool prompt_and_parse(ReqProDB_Artifact.MODE mode, out bool cancelled){cancelled = false;try{base.structure_only = true;string exportDateTime = System.DateTime.Now.ToString();Main.WriteOutput("EA Requirement export at " + exportDateTime, -1 );Main.WriteOutput("", -1);if (true == base.prompt_and_parse(mode, out cancelled)){if (Main.mustAbort)return false;Main.EA_Repository.EnsureOutputVisible(Main.GUI_OUTPUT_TAB_NAME);// Configure the ReqProDB artifact as a traceability artifact, but only if it appeared// as though it were created for the first time during the export, otherwise leave// it alone with its existing setting.if (RQ_Artifact.get_mode(RQ_Element) == ReqProDB_Artifact.MODE.UNDEFINED)RQ_Artifact.set_traceability_mode(RQ_Element);ExportToReqPro(exportDateTime, out cancelled);return true;}}catch (Exception ex){Main.MessageBoxException(ex, "Exception (parse)");}return false;}/// <summary>/// Method called by the base class to convey the user selections made controlling the export/// operation./// </summary>/// <param name="selectedObject"></param>/// <param name="createFolder"></param>/// <param name="folderName"></param>/// <param name="requirementType"></param>/// <param name="requirementStatus"></param>protected override void provideExportDecisionsToClient(ReqPro_object selectedObject,bool createFolder,string folderName,string requirementType,ExportForm.ExportExtent exportExtent){m_SelectedObject = selectedObject;m_CreateFolder = createFolder;m_FolderName = folderName;// The requirement type display string in the export form is like "some requirement type(abbrev)"// We want just the abbrev so use string splitting to extract it.char [] delim = {'('};string [] tokens = requirementType.Split(delim, 2);delim[0] = ')';m_ReqType = tokens[1].Split(delim,2)[0];m_ExportExtent = exportExtent;}private void ExportToReqPro(string exportDateTime, out bool cancelled){cancelled = false;try{ArrayList ea_reqs; // list of new requirements for export - assigned later from element accumulatorArrayList ea_mastered_reqs = new ArrayList();ArrayList ea_mastered_reqs_rp_guids = new ArrayList();// Read tag from ReqProDB element that enables/disables the capability to use EA as a master// repository for requirements originally created in EA. If the tag does not exist, EA mastering// will be allowed by default.bool EA_MasteringAllowed = EA_TaggedValues.Read(base.RQ_Element, Constants.TAG_EA_MASTERING_ALLOWED, Constants.DEFAULT_EA_MASTERING_ALLOWED);#region DETERMINE PARENT PACKAGE// Obtain the EA parent package so that we can scan it for existing requirement elements.EA.Package parentPackage;if (m_ExportExtent == ExportForm.ExportExtent.PACKAGE_REQS){parentPackage = EA_Utilities.get_selected_package();}else{// default to the ReqProDB container package. This is probably what most exports// will use.parentPackage = Main.EA_Repository.GetPackageByID( base.RQ_Element.PackageID );}#endregion#region GET_EXPORT_LISTMain.WriteOutput("Acquiring list of requirement elements in EA", -1);// setup the element types list to control the element accumulationArrayList allowedElementTypes = new ArrayList();allowedElementTypes.Add("Requirement");//allowedElementTypes.Add("UseCase");if (m_ExportExtent != ExportForm.ExportExtent.SINGLE_REQ){// create the element accumulator, and use it to find all the requirement// elements in the container packageElementAccumulator reqLister = new ElementAccumulator(allowedElementTypes);EA_Utilities.findAndProcessPackageElements( parentPackage, reqLister, true );if (Main.mustAbort)return;// Remove requirements from the accumulated list if they have already been linked// to ReqPro requirement elements, by virtue of them seeming to have a valid GUID// We dont actually validate the GUID, just check that one is present or not.ea_reqs = reqLister.Elements;int i_ea_reqs;for (i_ea_reqs = 0; i_ea_reqs < ea_reqs.Count; ) // No index increment here{EA.Element ea_req = (EA.Element)ea_reqs[i_ea_reqs];string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID);if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){// found an EA requirement element that seems to already be linked to a// ReqPro requirement element// if the element seems to be one that was mastered (created) in EA and exported// to ReqPro on a previous export cycle, then collect it in a seperate list in case// we need to do an update on ReqPro later on.if (true == EA_TaggedValues.Read(ea_req, Constants.TAG_CREATED_IN_EA, Constants.DEFAULT_CREATED_IN_EA)){ea_mastered_reqs.Add(ea_req);ea_mastered_reqs_rp_guids.Add(GUID);}// discard from the export list.ea_reqs.RemoveAt(i_ea_reqs);continue;}i_ea_reqs++; // index increment here}if (Main.mustAbort)return;}else // user wants to export a single selected requirement{EA.Element ea_ele = EA_Utilities.get_selected_element(allowedElementTypes);if (ea_ele == null){MessageBoxEx.Show("The export extent chosen (single requirement export)\n" +"is not compatible with the item selected in the EA\n" +"project browser. You must select a requirement object\n" +"to use this export extent.","Error");cancelled = true;return;}string GUID = EA_TaggedValues.Read(ea_ele, Constants.TAG_GUID);if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){MessageBoxEx.Show("The requirement object selected in the EA project browser,\n" +"already appears to be associated with a ReqPro object.","Error");cancelled = true;return;}ea_reqs = new ArrayList();ea_reqs.Add(ea_ele);}#endregion// Export newly mastered EA requirements to ReqProif (false == export_new_EA_mastered_requirements(ref ea_reqs, ref ea_mastered_reqs, ref ea_mastered_reqs_rp_guids, out cancelled))return;// If the ReqProDB element informs us that EA mastering of requirements is allowed,// then we can process the update of any requirements in ReqPro that are linked to// requirements in EA, that seem to have originally been created in EA.if (EA_MasteringAllowed){if (false == update_old_EA_mastered_requirements(ref ea_mastered_reqs, out cancelled))return;}// Export/Update Requirement relationshipsexport_new_EA_mastered_requirement_relationships(ref ea_reqs);if (EA_MasteringAllowed){update_old_EA_mastered_requirement_relationships(ref ea_mastered_reqs);}Main.EA_Repository.RefreshModelView(parentPackage.PackageID);// Use historical data stored in the ReqProDB element to determine if any EA mastered requirements// have been deleted, leaving orphans in the ReqPro database that might need to be cleaned upreport_orphaned_ReqPro_requirements(ref ea_mastered_reqs_rp_guids);Main.WriteOutput("Export Completed",-1);MessageBoxEx.Show("Export Completed");}catch (Exception ex){Main.MessageBoxException(ex, "Exception (ExportToReqPro)");}}/// <summary>/// Exports newly EA mastered requirements to ReqPro/// </summary>/// <param name="ea_reqs"></param>/// <param name="ea_mastered_reqs"></param>/// <param name="ea_mastered_reqs_rp_guids"></param>/// <param name="cancelled"></param>/// <returns></returns>private bool export_new_EA_mastered_requirements(ref ArrayList ea_reqs,ref ArrayList ea_mastered_reqs,ref ArrayList ea_mastered_reqs_rp_guids,out bool cancelled){cancelled = false;// if there are any new requirements to exportif (ea_reqs.Count > 0){Main.WriteOutput(string.Format("Found {0} Requirements for export.", ea_reqs.Count), -1);ReqPro40.Requirements req_collection = ReqProDatabase.get_requirements();if (req_collection == null){MessageBoxEx.Show("Could not acquire Requirement Collection\n" +"from ReqPro database.\n", "Error");cancelled = true;return false;}ReqPro40.Package rp_pkg = null;// Obtain the ReqPro package selected by the user (if any)if (this.m_SelectedObject != null){rp_pkg = ReqProDatabase.get_package(this.m_SelectedObject.iKey);if (this.m_CreateFolder){ReqPro40.Package rp_sub_pkg = ReqProDatabase.create_sub_package(rp_pkg, this.m_FolderName, "");if (rp_sub_pkg != null){rp_pkg = rp_sub_pkg;}}}// process each requirement found in EA that needs exportingforeach(EA.Element ea_req in ea_reqs){// get EA requirement without any temporary tag that the modeller may have given itstring tag = null;string ea_req_untagged_name = untaggedReqName(ea_req.Name, ref tag, false);Main.WriteOutput("Exporting : " + ea_req.Name, ea_req.ElementID);// Add the requirement to ReqPro requirement collectionReqPro40.Requirement rp_req = ReqProDatabase.add_requirement(req_collection, ea_req_untagged_name, ea_req.Notes, this.m_ReqType);if (rp_req != null){// Get the tag for the new requirement from ReqPro and use it to form a new name for// the EA requirement. Note that at this point in time the tag has a pending form. It// only becomes correct once we do a rq_req.Save() later on, so this update has to be// repeated later. This first update is just to confirm that we can actually do an// update in EA, before we commit the changes to the ReqPro database.string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);ea_req.Name = rp_req_tag + " " + ea_req_untagged_name;// Test that the EA requirement can be updated.if (false == ea_req.Update()){MessageBoxEx.Show("Failed to update EA requirement element.\n" +"Check that the EA model is writeable.\n" +"Check that the EA model is not locked by another user.\n" +"Check that the EA requirement element is not currently being edited.\n\n" +"Cancelling export - please retry once checks have been performed.", "Error");cancelled = true;return false;}// Commit changes to ReqPro databaserp_req.Save();// Now locate the new requirement under the selected package in ReqProif (rp_pkg != null){rp_pkg.AddElement(rp_req, ReqPro40.enumPackageLookups.ePackageLookup_Object, ReqPro40.enumElementTypes.eElemType_Requirement);}// If the EA requirement has a parent requirement, then in ReqPro we must organise it such// that it has a parent-child hierarchical relationshipif (ea_req.ParentID != 0){EA.Element parent_ea_req = Main.EA_Repository.GetElementByID(ea_req.ParentID);if (parent_ea_req != null){// get GUID of ReqPro parent requirementstring parent_guid = EA_TaggedValues.Read(parent_ea_req, Constants.TAG_GUID);if (parent_guid != null && parent_guid.Length > 0 && parent_guid.StartsWith("{")){// Get the parent ReqPro requirementReqPro40.Requirement parent_rp_req = ReqProDatabase.get_requirement_by_guid(parent_guid);if (parent_rp_req != null){// Establish relationship in ReqProrp_req.AssignParent(parent_rp_req, ReqPro40.enumRequirementLookups.eReqLookup_Object);// Even though in EA, a parent-child relationship exists, we want to re-enforce that// with a connection relationship too, so that when the parent and child exists on// a diagram, they are shown linked together.EA_Utilities.add_connection(parent_ea_req, ea_req);}}}}// Now re-acquire the tag, which should no longer be in a pending form but have a real number// assigned to it as a result of the commit we just did above.rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);// Attempt to set any attributes in the new ReqPro requirement.exportAttributes(rp_req, ea_req, rp_req_tag);rp_req.Save();// Update the EA requirement for the second time, now with the correct and final tagea_req.Name = rp_req_tag + " " + ea_req_untagged_name;ea_req.Update();Main.WriteOutput(" (Re)Assigned Tag : " + ea_req.Name, ea_req.ElementID);// Record the GUID and tag in EA tagged values. This will effectively bind the EA requirement// to its new ReqPro requirement counterpart.EA_TaggedValues.Write(ea_req, Constants.TAG_GUID, rp_req.GUID);EA_TaggedValues.Write(ea_req, Constants.TAG_TAG, rp_req_tag);// Save in the list of ReqPro GUIDs to support ReqPro orphaned requirement detection later onea_mastered_reqs_rp_guids.Add(rp_req.GUID);// mark the requirement as having been created in EA.EA_TaggedValues.Write(ea_req, Constants.TAG_CREATED_IN_EA, true);// Update the ReqPro collection.req_collection.Save();}}// Save details of the ReqPro package where the requirements were exported to. This info can be// used on the next export to auto-select the ReqPro destination package for the export, etc.if (rp_pkg != null){EA_TaggedValues.Write(base.RQ_Element, Constants.TAG_LAST_EXPORT_GUID, rp_pkg.GUID);EA_TaggedValues.Write(base.RQ_Element, Constants.TAG_LAST_EXPORT_NAME, rp_pkg.Name);}else{// export occurred to the root package.EA_TaggedValues.Delete(base.RQ_Element, Constants.TAG_LAST_EXPORT_GUID);EA_TaggedValues.Delete(base.RQ_Element, Constants.TAG_LAST_EXPORT_NAME);}}else{Main.WriteOutput("Found no new requirements to add to ReqPro",-1);}Main.WriteSeperator();return true;}/// <summary>/// Updates ReqPro requirements that have masters in EA/// </summary>/// <param name="ea_mastered_reqs"></param>/// <param name="cancelled"></param>/// <returns></returns>private bool update_old_EA_mastered_requirements(ref ArrayList ea_mastered_reqs,out bool cancelled){cancelled = false;// if there are any EA mastered requirements...if (ea_mastered_reqs.Count > 0){bool possibleOrphans = false;Main.WriteOutput(string.Format("Found {0} Requirements to update.", ea_mastered_reqs.Count), -1);ReqPro40.Requirements req_collection = ReqProDatabase.get_requirements();// process each EA mastered requirementint i_ea_mastered_reqs = 0;for (i_ea_mastered_reqs = 0; i_ea_mastered_reqs < ea_mastered_reqs.Count; ) // NOTE: no count increment done here{EA.Element ea_req = (EA.Element)ea_mastered_reqs[i_ea_mastered_reqs];// make sure there is a GUIDstring GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID);if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){ReqPro40.Requirement rp_req;// Try and find the requirement in ReqProrp_req = ReqProDatabase.get_requirement_by_guid(GUID);if (rp_req != null){// copy name and notes from EA to ReqProstring tag = null;string ea_req_untagged_name = untaggedReqName(ea_req.Name, ref tag, true);// Test that the EA requirement can be updated.ea_req.Name = ea_req_untagged_name;ea_req.Update();if (false == ea_req.Update()){MessageBoxEx.Show("Failed to update EA requirement element.\n" +"Check that the EA model is writeable.\n" +"Check that the EA model is not locked by another user.\n" +"Check that the EA requirement element is not currently being edited.\n\n" +"Cancelling export - please retry once checks have been performed.", "Error");cancelled = true;return false;}// copy content to the existing ReqPro requirementrp_req.Name = ea_req_untagged_name;rp_req.Text = ea_req.Notes;string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);// Attempt to set any attributes in the existing ReqPro requirement.exportAttributes(rp_req, ea_req, rp_req_tag);// Commit changes to ReqPro databaserp_req.Save();// Although we are allowing EA to be the master repository of requirements// if they were originally created in EA, we still want to use ReqPro as the// master for any numbering scheme (ie. tags), so update the EA requirements// Tag as necessary.ea_req.Name = rp_req_tag + " " + ea_req_untagged_name;ea_req.Update();EA_TaggedValues.Write(ea_req, Constants.TAG_TAG, rp_req_tag);Main.WriteOutput("Updated : " + ea_req.Name, ea_req.ElementID);}else{possibleOrphans = true;Main.WriteOutput("Warning, failed to find ReqPro requirement counterpart (possible orphan?)", ea_req.ElementID);}i_ea_mastered_reqs++;}else{ea_mastered_reqs.RemoveAt(i_ea_mastered_reqs);// do not increment i_ea_mastered_reqs after here}}Main.WriteSeperator();if (possibleOrphans == true){Main.WriteOutput("", -1);Main.WriteOutput("One or more possible orphans have been found", -1);Main.WriteOutput("This could be the result of someone accidentally deleting the requirement", -1);Main.WriteOutput("in the ReqPro database. Or, it could be that someone modified the GUID tagged", -1);Main.WriteOutput("value in EA or ReqPro (very naughty).",-1);Main.WriteOutput("", -1);Main.WriteOutput("Going forward, if the requirement must be retained, delete all of its tagged values,", -1);Main.WriteOutput("in EA, remove the tag from its name, and attempt another export. The EA requirement will", -1);Main.WriteOutput("be given a new tag number, but at least it will re-appear in the ReqPro database.", -1);Main.WriteOutput("", -1);Main.WriteOutput("If the requirement is no longer needed, it can be deleted from EA once any design", -1);Main.WriteOutput("impacts are understood.", -1);Main.WriteSeperator();}}else{Main.WriteOutput("No ReqPro requirements need updating from their EA masters.",-1);Main.WriteSeperator();}return true;}/// <summary>/// Export relationships for the new requirements exported from EA/// </summary>/// <param name="ea_reqs"></param>private void export_new_EA_mastered_requirement_relationships(ref ArrayList ea_reqs){// Algorithm design://// for each new EA requirement (EA.Req) exported// Get the ReqPro equivalent requirement (RP.Req)// for each connector (EA.C) in EA.Req// get referenced requirement (EA.RefReq) from EA.C// find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro// Establish a traces to relationship from RP.RefReq to RP.ReqMain.WriteOutput("Creating Trace Relationships",-1);// for each new EA requirement (EA.Req) exportedforeach (EA.Element ea_req in ea_reqs){Main.WriteOutput(" " + ea_req.Name, ea_req.ElementID);string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID, "");if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){// Get the ReqPro equivalent requirement (RP.Req)ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(GUID);if (rp_req != null){// for each connector (EA.C) in EA.Reqforeach(EA.Connector ea_c in ea_req.Connectors){int destId = -1;// we dont care about direction of relationship, so test for bothif (ea_c.ClientID == ea_req.ElementID)destId = ea_c.SupplierID;else if (ea_c.SupplierID == ea_req.ElementID)destId = ea_c.ClientID;// and make sure we filter out self-referential connectorsif (destId != ea_req.ElementID){// get referenced requirement (EA.RefReq) from EA.CEA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);if (ea_ref_req != null && ea_ref_req.Type.Equals("Requirement")){// Get the GUID from the referenced elementGUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){// find EA.RefReq's equivalent requirement (RP.RefReq) in ReqProReqPro40.Requirement rp_ref_req = ReqProDatabase.get_requirement_by_guid(GUID);if (rp_ref_req != null){// Establish a traces to relationship from RP.RefReq to RP.ReqReqPro40.Relationships rp_ref_req_c = (ReqPro40.Relationships)rp_ref_req.TracesTo;if (rp_ref_req_c != null){// wrap the relationship add in exception handling - In EA, a parent child relationship// can exist by virtue of the elements parentID values, and such does not prevent the// existence of a connection relationship either. But in ReqPro, it does. Once a requirement// has a "hierarchical" relationship, you cannot establish the same relationship in a 2nd// way, using for example a TracesTo relationship. Using exception handling here is probably// quicker than trying to examine what relationships already exist and act accordingly.try{ReqPro40.Relationship rp_ref_req_rel =rp_ref_req_c.Add(rp_req,ReqPro40.enumRequirementLookups.eReqLookup_Object,null, ReqPro40.enumRelatedProjectLookups.eRelProjLookup_Empty,false);if (rp_ref_req_rel != null){// commitrp_ref_req.Save();}}catch{}}}}}}}}}}Main.WriteSeperator();}/// <summary>/// Update ReqPro relationships for requirements mastered in EA/// </summary>/// <param name="ea_mastered_reqs"></param>private void update_old_EA_mastered_requirement_relationships(ref ArrayList ea_mastered_reqs){// Algorithm design://// for each EA requirement (EA.Req) updated// Get the ReqPro equivalent requirement (RP.Req)// for each connector (EA.C) in EA.Req// get referenced requirement (EA.RefReq) from EA.C// find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro// Establish a traces to relationship from RP.RefReq to RP.Req (if it does not already exist)//// for each trace-to relationship (RP.C) in RP.Req// if relationship does not exist in EA.Req// delete RP.C//// for each trace-from relationship (RP.C) in RP.Req// if relationship does not exist in EA.Req// delete RP.C//Main.WriteOutput("Updating Trace Relationships",-1);// for each EA requirement (EA.Req) updatedforeach(EA.Element ea_req in ea_mastered_reqs){Main.WriteOutput(" " + ea_req.Name, ea_req.ElementID);string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID, "");if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){// Get the ReqPro equivalent requirement (RP.Req)ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(GUID);if (rp_req != null){// for each connector (EA.C) in EA.Reqforeach(EA.Connector ea_c in ea_req.Connectors){int destId = -1;// we dont care about direction of relationship, so test for bothif (ea_c.ClientID == ea_req.ElementID)destId = ea_c.SupplierID;else if (ea_c.SupplierID == ea_req.ElementID)destId = ea_c.ClientID;// and make sure we filter out self-referential connectorsif (destId != ea_req.ElementID){// get referenced requirement (EA.RefReq) from EA.CEA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);if (ea_ref_req != null && ea_ref_req.Type.Equals("Requirement")){// Get the GUID from the referenced elementGUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){// find EA.RefReq's equivalent requirement (RP.RefReq) in ReqProReqPro40.Requirement rp_ref_req = ReqProDatabase.get_requirement_by_guid(GUID);if (rp_ref_req != null){// Establish a traces to relationship from RP.RefReq to RP.Req (if it does not already exist)ReqPro40.Relationships rp_ref_req_c = (ReqPro40.Relationships)rp_ref_req.TracesTo;if (rp_ref_req_c != null){// ReqPro throws an exception if you try to create a relationship that already exists.// ReqPro doesn't seem to give any easy way to ask the question, "does a relationship// exist between A and B". It is debatable whether running a hand written function to// answer the question is going to be any quicker than just catching the exceptions// and ignoring them. For now though, use exception handling in this very bad way.try{ReqPro40.Relationship rp_ref_req_rel =rp_ref_req_c.Add(rp_req,ReqPro40.enumRequirementLookups.eReqLookup_Object,null, ReqPro40.enumRelatedProjectLookups.eRelProjLookup_Empty,false);if (rp_ref_req_rel != null){// commitrp_ref_req.Save();Main.WriteOutput(" Created Trace Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);}}catch{// do nothing}}}}}}}// Examine the Traces-To relationships in ReqProint limit_numberOfTraceTo = 0;if (true == rp_req.get_HasTracesTo(ref limit_numberOfTraceTo)){ReqPro40.Relationships rp_req_c = (ReqPro40.Relationships)rp_req.TracesTo;if (rp_req_c != null){// for each relationship (RP.C) in RP.Reqrp_req_c.MoveFirst();int i_numberOfTraceTo;for (i_numberOfTraceTo = 0; i_numberOfTraceTo < limit_numberOfTraceTo; i_numberOfTraceTo++){// Obtain the sub-requirement from the relationship, and parse itReqPro40.Relationship rp_req_rel = rp_req_c.GetCurrentRelationship();ReqPro40.Requirement rp_ref_req =rp_req_rel.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);if (rp_ref_req != null){// if relationship does not exist in EA.Reqif (!ea_element_traces_to_or_from(ea_req, rp_ref_req.GUID)){// delete RP.Crp_req_rel.Delete();Main.WriteOutput(" Deleted Trace-To Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);}}rp_req_c.MoveNext();}// commitrp_req.Save();}}// Examine the Traces-From relationships in ReqProint limit_numberOfTraceFrom = 0;if (true == rp_req.get_HasTracesFrom(ref limit_numberOfTraceFrom)){ReqPro40.Relationships rp_req_c = (ReqPro40.Relationships)rp_req.TracesFrom;if (rp_req_c != null){// for each relationship (RP.C) in RP.Reqrp_req_c.MoveFirst();int i_numberOfTraceFrom;for (i_numberOfTraceFrom = 0; i_numberOfTraceFrom < limit_numberOfTraceFrom; i_numberOfTraceFrom++){// Obtain the sub-requirement from the relationship, and parse itReqPro40.Relationship rp_req_rel = rp_req_c.GetCurrentRelationship();ReqPro40.Requirement rp_ref_req =rp_req_rel.get_SourceRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);if (rp_ref_req != null){// if relationship does not exist in EA.Reqif (!ea_element_traces_to_or_from(ea_req, rp_ref_req.GUID)){// delete RP.Crp_req_rel.Delete();Main.WriteOutput(" Deleted Trace-From Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);}}rp_req_c.MoveNext();}// commitrp_req.Save();}}}}}Main.WriteSeperator();}/// <summary>/// Use historical data stored in the ReqProDB element to/// </summary>/// <param name="ea_mastered_reqs_rp_guids"></param>private void report_orphaned_ReqPro_requirements(ref ArrayList ea_mastered_reqs_rp_guids){// we can only report on EA mastered requirements that have been deleted, if the extent of// the export is total, not partialif (m_ExportExtent == ExportForm.ExportExtent.REQPRODB_REQS){// Get the last list of EA mastered requirements from the ReqProDB elementif (base.RQ_Element.Notes != null && base.RQ_Element.Notes.Length > 0){// split it into a string arraychar [] seperators = {'\r','\n'};string [] options = base.RQ_Element.Notes.Split(seperators);ArrayList rp_orphaned_reqs = new ArrayList();ArrayList rp_non_orphaned_reqs = new ArrayList();// process the string array to accumulate list of orphaned and non-orphaned requirementsforeach (string s in options){string trimmed_s = s.Trim();if (trimmed_s.Length > 0){if (trimmed_s.StartsWith(Constants.KEY_EXPORTED_GUID)){string value = trimmed_s.Substring(Constants.KEY_EXPORTED_GUID.Length);if (false == ea_mastered_reqs_rp_guids.Contains(value)){rp_orphaned_reqs.Add(value);}else{rp_non_orphaned_reqs.Add(value);}}}}// default decision to use when constructing export options for ReqProDB element later onDialogResult dlgRes = DialogResult.No;// report on orphaned requirementsif (rp_orphaned_reqs.Count > 0){ArrayList rp_orphaned_req_strings = new ArrayList();foreach(string s in rp_orphaned_reqs){ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(s);if (rp_req != null){string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);if (rp_req_tag != null){rp_orphaned_req_strings.Add(" " + rp_req_tag + " " + rp_req.Name);}}}if (rp_orphaned_req_strings.Count > 0){Main.WriteOutput("The following EA Mastered requirements in ReqPro, may no longer be needed.", -1);Main.WriteOutput("i.e. they are orphaned requirements in ReqPro, because they have been deleted", -1);Main.WriteOutput("in EA since the last export.", -1);Main.WriteOutput("Please verify and if necessary, mark them as obsolete in ReqPro.", -1);foreach(string s in rp_orphaned_req_strings){Main.WriteOutput(s, -1);}Main.WriteSeperator();// allow user to specifiy whether we should forget about the orphaned requirements// the next time we do an export.dlgRes = MessageBoxEx.Show("Some ReqPro requirements have been orphaned (see output\n" +"tab display for more information).\n" +"Ignore these problems in future exports?", "Confirm", MessageBoxButtons.YesNo);}}StringBuilder sb = new StringBuilder();// reconstruct non-export related options using the appropriate ReqProFilterForm static method// That method keeps knowledge of the import filter options localised in the right place.ReqProFilterForm.saveFilterSettings(options, ref sb);// If this export had nothing to work with from the ReqProDB options....if (rp_orphaned_reqs.Count == 0 && rp_non_orphaned_reqs.Count == 0){// The options did not contain any key values. That probably means that up till now,// any export that has been performed previously, did not actually export anything.// So, just add whatever we exported this time (if anything)if (ea_mastered_reqs_rp_guids.Count > 0){sb.Append(Constants.EXPORT_HEADING);foreach (string s in ea_mastered_reqs_rp_guids){sb.Append(Constants.KEY_EXPORTED_GUID);sb.Append(s);sb.Append("\r\n");}}}else{sb.Append(Constants.EXPORT_HEADING);// construct export-related optionsif (dlgRes == DialogResult.No){foreach (string s in rp_orphaned_reqs){sb.Append(Constants.KEY_EXPORTED_GUID);sb.Append(s);sb.Append("\r\n");}}foreach (string s in rp_non_orphaned_reqs){sb.Append(Constants.KEY_EXPORTED_GUID);sb.Append(s);sb.Append("\r\n");// if this item is in ea_mastered_reqs_rp_guids, then remove it from there so that we do not// duplicate it in the options string when we process ea_mastered_reqs_rp_guids after this loop// completesif (ea_mastered_reqs_rp_guids.Contains(s)){ea_mastered_reqs_rp_guids.Remove(s);}}// If there are any items left in ea_mastered_reqs_rp_guids, add them tooforeach (string s in ea_mastered_reqs_rp_guids){sb.Append(Constants.KEY_EXPORTED_GUID);sb.Append(s);sb.Append("\r\n");}}base.RQ_Element.Notes = sb.ToString();base.RQ_Element.Update();}}}private bool ea_element_traces_to_or_from(EA.Element ea_req, string rp_GUID){foreach(EA.Connector ea_c in ea_req.Connectors){int destId = -1;// we dont care about direction of relationship, so test for bothif (ea_c.ClientID == ea_req.ElementID)destId = ea_c.SupplierID;else if (ea_c.SupplierID == ea_req.ElementID)destId = ea_c.ClientID;// and make sure we filter out self-referential connectorsif (destId != ea_req.ElementID){EA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);if (ea_ref_req != null){string GUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{")){if (rp_GUID.Equals(GUID))return true;}}}}return false;}/// <summary>/// Look for and strip any temporary tag from the requirement name, returning a new/// string to be used as the requirement name/// </summary>/// <param name="taggedReqName"></param>/// <returns></returns>private string untaggedReqName(string taggedReqName, ref string tag, bool force){if (taggedReqName != null){// Try and split the string into two tokens at the first space characterchar [] delim = {' '};string [] tokens = taggedReqName.Split(delim, 2);// if there are two tokens resulting from the splitif (tokens.GetLength(0) == 2){// return tagtag = tokens[0];// if the first token appears to be a tagif (force == true|| tokens[0].StartsWith("REQ")|| tokens[0].StartsWith("TAG")|| tokens[0].StartsWith("SPR")|| tokens[0].StartsWith("<")|| (tokens[0].IndexOfAny(numbers) > 0 && tokens[0].IndexOfAny(letters) == 0)){// return the token after the tag.return tokens[1];}}}// default to the input stringreturn taggedReqName;}private string tagPrefix(string tag){if (tag != null && tag.Length > 0){string[] prefixes = tag.Split("0123456789.".ToCharArray());if (prefixes.GetLength(0) > 0){return prefixes[0];}}return tag;}private void exportAttributes(ReqPro40.Requirement rp_req, EA.Element ea_req, string rp_req_tag){// Update the attributes of a ReqPro requirement. We have to be very careful here.// ReqPro does not like us trying to set the value of attributes that do not exist for the// specified requirement type, and it also does not like us trying to set an attribute that is// a list type, to a value that is not in the predefined set of values for the list type.bool hasStatus = false;bool hasDifficulty = false;bool hasPriority = false;bool hasSource = false;bool hasSourceVersion = false;bool hasSourceSection = false;bool hasSubsystem = false;bool hasStability = false;bool hasType = false;string reqType = tagPrefix(rp_req_tag);// Use the ReqProParser's knowledge of requirement types and attribute type associations to tell// us what attributes we can set, and then use the setListItemValue() function to do the setting.// That function knows how to set List items correctly and safely so as to not cause exceptions// to be raised in the ReqPro automation onject.if (reqTypeHasOneOrMoreAttrs(reqType,ref hasStatus, ref hasDifficulty, ref hasPriority,ref hasSource, ref hasSourceVersion, ref hasSourceSection,ref hasSubsystem, ref hasStability, ref hasType)){if (hasStatus){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_STATUS, ea_req.Status, rp_req_tag);}if (hasDifficulty){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_DIFFICULTY, ea_req.Difficulty, rp_req_tag);}if (hasPriority){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_PRIORITY, ea_req.Priority, rp_req_tag);}if (hasSource){string s = EA_TaggedValues.Read(ea_req, Constants.TAG_SOURCE);if (s != null && s.Length > 0){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_SOURCE, s, rp_req_tag);}}if (hasSourceVersion){string s = EA_TaggedValues.Read(ea_req, Constants.TAG_SOURCE_VERSION);if (s != null && s.Length > 0){setTextAttrValue(rp_req, ea_req, Constants.RP_ATTR_SOURCE_VERSION, s, rp_req_tag);}}if (hasSourceSection){string s = EA_TaggedValues.Read(ea_req, Constants.TAG_SOURCE_SECTION);if (s != null && s.Length > 0){setTextAttrValue(rp_req, ea_req, Constants.RP_ATTR_SOURCE_SECTION, s, rp_req_tag);}}if (hasSubsystem){string s = EA_TaggedValues.Read(ea_req, Constants.TAG_SUBSYSTEM);if (s != null && s.Length > 0){// The tagged value may be a comma seperated list of subsystem names so break it up// and process each one foundstring[] sa = s.Split(",".ToCharArray());foreach (string sas in sa){string trimmed_sas = sas.Trim();if (trimmed_sas.Length > 0){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_SUBSYSTEM_TYPE, trimmed_sas, rp_req_tag);}}}}if (hasStability){string s = EA_TaggedValues.Read(ea_req, Constants.TAG_STABILITY);if (s != null && s.Length > 0){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_STABILITY, s, rp_req_tag);}}if (hasType){// The StereoTypeEx is a comma seperated list, and the first in the list is usually (always?)// the one displayed in EA's project browser, so try and export the first item in the listbool done = false;if (ea_req.StereotypeEx != null && ea_req.StereotypeEx.Length > 0){string[] s_arr = ea_req.StereotypeEx.Split(",".ToCharArray());if (s_arr[0] != null && s_arr[0].Length > 0){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_REQ_TYPE, s_arr[0], rp_req_tag);done = true;}}// if we didnt get anything from StereoTypeEx, then try Stereotypeif (!done && ea_req.Stereotype != null && ea_req.Stereotype.Length > 0){setListItemAttrValue(rp_req, ea_req, Constants.RP_ATTR_REQ_TYPE, ea_req.Stereotype, rp_req_tag);}}}}/// <summary>/// Set a ReqPro requirement attribute value, for an attribute that is a list type./// This function only allows the setting of the value, if it is one of the values/// allowed for the list item. This ensures we do not get an exception raised in the/// ReqPro automation object./// </summary>/// <param name="rp_req"></param>/// <param name="label"></param>/// <param name="value"></param>private void setListItemAttrValue(ReqPro40.Requirement rp_req, EA.Element ea_req, string label, string value, string rp_req_tag){bool attribute_type_found = false;bool attribute_value_found = false;// look through each attribute value, for the one whose label matches the one specifiedReqPro40.AttrValues rp_attr_values = rp_req.AttrValues;foreach (ReqPro40.AttrValue rp_attr_value in rp_attr_values){if (rp_attr_value != null && rp_attr_value.Label.Equals(label)){attribute_type_found = true;// Look through each list item value to make sure that one exists that matches// the value specifiedReqPro40.ListItemValues rp_list_item_values = rp_attr_value.ListItemValues;if (rp_list_item_values != null){foreach (ReqPro40.ListItemValue rp_list_item_value in rp_list_item_values){if (rp_list_item_value.Text.Equals(value)){// We found that the list contains the value specified, so set the value of the attributerp_list_item_value.Selected = true;attribute_value_found = true;// exit inner loopbreak;}}}// exit outer loopbreak;}}if (!attribute_type_found){Main.WriteOutput(string.Format("WARNING, Failed to export attribute type ({0}) for ({1})",label, rp_req_tag), ea_req.ElementID);}if (!attribute_value_found){Main.WriteOutput(string.Format("WARNING, Failed to export attribute type/value ({0}/{1}) for ({2})",label, value, rp_req_tag), ea_req.ElementID);}}/// <summary>/// Set a ReqPro requirement attribute value, for an attribute that is a text type./// </summary>/// <param name="rp_req"></param>/// <param name="label"></param>/// <param name="value"></param>private void setTextAttrValue(ReqPro40.Requirement rp_req, EA.Element ea_req, string label, string value, string rp_req_tag){bool attribute_type_found = false;// look through each attribute value, for the one whose label matches the one specifiedReqPro40.AttrValues rp_attr_values = rp_req.AttrValues;foreach (ReqPro40.AttrValue rp_attr_value in rp_attr_values){if (rp_attr_value != null && rp_attr_value.Label.Equals(label)){attribute_type_found = true;rp_attr_value.Text = value;// exit outer loopbreak;}}if (!attribute_type_found){Main.WriteOutput(string.Format("WARNING, Failed to export attribute type ({0}) for ({1})",label, rp_req_tag), ea_req.ElementID);}}}}