Subversion Repositories DevTools

Rev

Rev 2157 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2155 ghuddy 1
using System;
2
using System.Text;
3
using System.Globalization;
4
using System.Collections;
5
using System.Windows.Forms;
6
using ReqPro40;
7
 
8
namespace EA_ReqPro
9
{
10
	/// <summary>
11
   /// ExportToReqProDatabase is a specialisation of CopyReqProDatabaseToMemory, designed to copy the 
12
   /// ReqPro database content into memory, and allow a user to select certain aspects to control a
13
   /// subsequent export operation.
14
	/// </summary>
15
	public class ExportToReqProDatabase : CopyReqProDatabaseToMemory
16
	{
17
      private ReqPro_object m_SelectedObject;
18
      private bool m_CreateFolder;
19
      private string m_FolderName;
20
      private string m_ReqType;
21
      private ExportForm.ExportExtent m_ExportExtent;
22
 
23
      private static char [] numbers = "0123456789".ToCharArray();
24
      private static char [] letters = "abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXY".ToCharArray();
25
 
26
		public ExportToReqProDatabase()
27
		{
28
		}
29
 
30
 
31
      /// <summary>
32
      /// Method to parse a ReqPro database using the information in a ReqProDB artifact,
33
      /// assumed to be selected in EA's project browser prior to the method call.
34
      /// </summary>
35
      /// <param name="ea_repository"></param>
36
      /// <returns></returns>
37
      public override bool prompt_and_parse(ReqProDB_Artifact.MODE mode, out bool cancelled)
38
      {
39
         cancelled = false;
40
 
41
         try
42
         {
43
            base.structure_only = true;
44
 
45
            string exportDateTime = System.DateTime.Now.ToString();
46
 
47
            Main.WriteOutput("EA Requirement export at " + exportDateTime, -1 );
48
            Main.WriteOutput("", -1);
49
 
50
            if (true == base.prompt_and_parse(mode, out cancelled))
51
            {
52
               if (Main.mustAbort)
53
                  return false;
54
 
55
               Main.EA_Repository.EnsureOutputVisible(Main.GUI_OUTPUT_TAB_NAME);
56
 
57
               // Configure the ReqProDB artifact as a traceability artifact, but only if it appeared
58
               // as though it were created for the first time during the export, otherwise leave
59
               // it alone with its existing setting.
60
               if (RQ_Artifact.get_mode(RQ_Element) == ReqProDB_Artifact.MODE.UNDEFINED)
61
                  RQ_Artifact.set_traceability_mode(RQ_Element);
62
 
63
               ExportToReqPro(exportDateTime, out cancelled);
64
 
65
               return true;
66
            }
67
         }
68
         catch (Exception ex)
69
         {
70
            Main.MessageBoxException(ex, "Exception (parse)");
71
         }      
72
 
73
         return false;
74
      }
75
 
76
 
77
      /// <summary>
78
      /// Method called by the base class to convey the user selections made controlling the export
79
      /// operation.
80
      /// </summary>
81
      /// <param name="selectedObject"></param>
82
      /// <param name="createFolder"></param>
83
      /// <param name="folderName"></param>
84
      /// <param name="requirementType"></param>
85
      /// <param name="requirementStatus"></param>
86
      protected override void provideExportDecisionsToClient(ReqPro_object selectedObject,
87
         bool createFolder,
88
         string folderName,
89
         string requirementType,
90
         ExportForm.ExportExtent exportExtent)
91
      {
92
         m_SelectedObject = selectedObject;
93
         m_CreateFolder = createFolder;
94
         m_FolderName = folderName;
95
 
96
         // The requirement type display string in the export form is like "some requirement type(abbrev)"
97
         // We want just the abbrev so use string splitting to extract it.
98
         char [] delim = {'('};
99
         string [] tokens = requirementType.Split(delim, 2);
100
         delim[0] = ')';
101
         m_ReqType = tokens[1].Split(delim,2)[0];
102
 
103
         m_ExportExtent = exportExtent;
104
      }
105
 
106
 
107
      private void ExportToReqPro(string exportDateTime, out bool cancelled)
108
      {
109
         cancelled = false;
110
 
111
         try
112
         {
113
            ArrayList ea_reqs;   // list of new requirements for export - assigned later from element accumulator
114
            ArrayList ea_mastered_reqs = new ArrayList();
115
            ArrayList ea_mastered_reqs_rp_guids = new ArrayList();
116
 
117
            // Read tag from ReqProDB element that enables/disables the capability to use EA as a master
118
            // repository for requirements originally created in EA. If the tag does not exist, EA mastering
119
            // will be allowed by default.
120
            bool EA_MasteringAllowed = EA_TaggedValues.Read(base.RQ_Element, Constants.TAG_EA_MASTERING_ALLOWED, Constants.DEFAULT_EA_MASTERING_ALLOWED);
121
 
122
            #region DETERMINE PARENT PACKAGE
123
            // Obtain the EA parent package so that we can scan it for existing requirement elements.
124
            EA.Package parentPackage;
125
            if (m_ExportExtent == ExportForm.ExportExtent.PACKAGE_REQS)
126
            {
127
               parentPackage = EA_Utilities.get_selected_package();
128
            }
129
            else 
130
            {
131
               // default to the ReqProDB container package. This is probably what most exports
132
               // will use.
133
               parentPackage = Main.EA_Repository.GetPackageByID( base.RQ_Element.PackageID );
134
            }
135
            #endregion
136
 
137
            #region GET_EXPORT_LIST
138
            Main.WriteOutput("Acquiring list of elements already in EA", -1);
139
 
140
            // setup the element types list to control the element accumulation
141
            ArrayList allowedElementTypes = new ArrayList();
142
            allowedElementTypes.Add("Requirement");
143
            //allowedElementTypes.Add("UseCase");
144
 
145
            if (m_ExportExtent != ExportForm.ExportExtent.SINGLE_REQ)
146
            {
147
               // create the element accumulator, and use it to find all the requirement
148
               // elements in the container package
149
               ElementAccumulator reqLister = new ElementAccumulator(allowedElementTypes);
150
               EA_Utilities.findAndProcessPackageElements( parentPackage, reqLister, true );
151
 
152
               if (Main.mustAbort)
153
                  return;
154
 
155
               // Remove requirements from the accumulated list if they have already been linked
156
               // to ReqPro requirement elements, by virtue of them seeming to have a valid GUID
157
               // We dont actually validate the GUID, just check that one is present or not.
158
               ea_reqs = reqLister.Elements; 
159
               int i_ea_reqs;
160
               for (i_ea_reqs = 0; i_ea_reqs < ea_reqs.Count; ) // No index increment here
161
               {
162
                  EA.Element ea_req = (EA.Element)ea_reqs[i_ea_reqs];
163
 
164
                  string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID);
165
                  if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
166
                  {
167
                     // found an EA requirement element that seems to already be linked to a 
168
                     // ReqPro requirement element
169
 
170
                     // if the element seems to be one that was mastered (created) in EA and exported
171
                     // to ReqPro on a previous export cycle, then collect it in a seperate list in case
172
                     // we need to do an update on ReqPro later on.
173
                     if (true == EA_TaggedValues.Read(ea_req, Constants.TAG_CREATED_IN_EA, Constants.DEFAULT_CREATED_IN_EA))
174
                     {
175
                        ea_mastered_reqs.Add(ea_req);
176
                        ea_mastered_reqs_rp_guids.Add(GUID);
177
                     }
178
 
179
                     // discard from the export list.
180
                     ea_reqs.RemoveAt(i_ea_reqs);
181
                     continue;
182
                  }
183
                  i_ea_reqs++;   // index increment here
184
               }
185
 
186
               if (Main.mustAbort)
187
                  return;
188
            }
189
            else // user wants to export a single selected requirement
190
            {
191
               EA.Element ea_ele = EA_Utilities.get_selected_element(allowedElementTypes);
192
               if (ea_ele == null)
193
               {
194
                  MessageBoxEx.Show(
195
                     "The export extent chosen (single requirement export)\n" +
196
                     "is not compatible with the item selected in the EA\n" +
197
                     "project browser. You must select a requirement object\n" +
198
                     "to use this export extent.",
199
                     "Error");
200
                  cancelled = true;
201
                  return;
202
               }
203
 
204
               string GUID = EA_TaggedValues.Read(ea_ele, Constants.TAG_GUID);
205
               if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
206
               {
207
                  MessageBoxEx.Show(
208
                     "The requirement object selected in the EA project browser,\n" +
209
                     "already appears to be associated with a ReqPro object.",
210
                     "Error");
211
                  cancelled = true;
212
                  return;
213
               }
214
 
215
               ea_reqs = new ArrayList();
216
               ea_reqs.Add(ea_ele);
217
            }
218
            #endregion
219
 
220
            // Export newly mastered EA requirements to ReqPro
221
            if (false == export_new_EA_mastered_requirements(ref ea_reqs, ref ea_mastered_reqs, ref ea_mastered_reqs_rp_guids, out cancelled))
222
               return;
223
 
224
            // If the ReqProDB element informs us that EA mastering of requirements is allowed,
225
            // then we can process the update of any requirements in ReqPro that are linked to
226
            // requirements in EA, that seem to have originally been created in EA.
227
            if (EA_MasteringAllowed)
228
            {
229
               if (false == update_old_EA_mastered_requirements(ref ea_mastered_reqs, out cancelled))
230
                  return;
231
            }
232
 
233
            // Export/Update Requirement relationships
234
            export_new_EA_mastered_requirement_relationships(ref ea_reqs);
235
 
236
            if (EA_MasteringAllowed)
237
            {
238
               update_old_EA_mastered_requirement_relationships(ref ea_mastered_reqs);
239
            }
240
 
241
            Main.EA_Repository.RefreshModelView(parentPackage.PackageID);
242
 
243
            // Use historical data stored in the ReqProDB element to determine if any EA mastered requirements
244
            // have been deleted, leaving orphans in the ReqPro database that might need to be cleaned up
245
            report_orphaned_ReqPro_requirements(ref ea_mastered_reqs_rp_guids);
246
 
247
            Main.WriteOutput("Export Completed",-1);
248
            MessageBoxEx.Show("Export Completed");
249
         }
250
         catch (Exception ex)
251
         {
252
            Main.MessageBoxException(ex, "Exception (ExportToReqPro)");
253
         }
254
      }
255
 
256
 
257
      /// <summary>
258
      /// Exports newly EA mastered requirements to ReqPro
259
      /// </summary>
260
      /// <param name="ea_reqs"></param>
261
      /// <param name="ea_mastered_reqs"></param>
262
      /// <param name="ea_mastered_reqs_rp_guids"></param>
263
      /// <param name="cancelled"></param>
264
      /// <returns></returns>
265
      private bool export_new_EA_mastered_requirements(ref ArrayList ea_reqs, 
266
         ref ArrayList ea_mastered_reqs, 
267
         ref ArrayList ea_mastered_reqs_rp_guids, 
268
         out bool cancelled)
269
      {
270
         cancelled = false;
271
 
272
         // if there are any new requirements to export
273
         if (ea_reqs.Count > 0)
274
         {
275
            Main.WriteOutput(string.Format("Found {0} Requirements for export.", ea_reqs.Count), -1);
276
 
277
            ReqPro40.Requirements req_collection = ReqProDatabase.get_requirements();
278
            if (req_collection == null)
279
            {
280
               MessageBoxEx.Show("Could not acquire Requirement Collection\n" +
281
                  "from ReqPro database.\n", "Error");
282
               cancelled = true;
283
               return false;
284
            }
285
 
286
            ReqPro40.Package rp_pkg = null;
287
 
288
            // Obtain the ReqPro package selected by the user (if any)
289
            if (this.m_SelectedObject != null)
290
            {
291
               rp_pkg = ReqProDatabase.get_package(this.m_SelectedObject.iKey);
292
 
293
               if (this.m_CreateFolder)
294
               {
295
                  ReqPro40.Package rp_sub_pkg = ReqProDatabase.create_sub_package(rp_pkg, this.m_FolderName, "");
296
                  if (rp_sub_pkg != null)
297
                  {
298
                     rp_pkg = rp_sub_pkg;
299
                  }
300
               }
301
            }
302
 
303
            // process each requirement found in EA that needs exporting
304
            foreach(EA.Element ea_req in ea_reqs)
305
            {
306
               // get EA requirement without any temporary tag that the modeller may have given it
307
               string ea_req_untagged_name = untaggedReqName(ea_req.Name, false);
308
 
309
               Main.WriteOutput("Exporting : " + ea_req.Name, ea_req.ElementID);
310
 
311
               // Add the requirement to ReqPro requirement collection
312
               ReqPro40.Requirement rp_req = ReqProDatabase.add_requirement(req_collection, ea_req_untagged_name, ea_req.Notes, this.m_ReqType);
313
               if (rp_req != null)
314
               {
315
                  // Get the tag for the new requirement from ReqPro and use it to form a new name for 
316
                  // the EA requirement. Note that at this point in time the tag has a pending form. It
317
                  // only becomes correct once we do a rq_req.Save() later on, so this update has to be
318
                  // repeated later. This first update is just to confirm that we can actually do an 
319
                  // update in EA, before we commit the changes to the ReqPro database.
320
                  string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
321
 
322
                  ea_req.Name = rp_req_tag + " " + ea_req_untagged_name;
323
 
324
                  // Test that the EA requirement can be updated.
325
                  if (false == ea_req.Update())
326
                  {
327
                     MessageBoxEx.Show(
328
                        "Failed to update EA requirement element.\n" +
329
                        "Check that the EA model is writeable.\n" +
330
                        "Check that the EA model is not locked by another user.\n" +
331
                        "Check that the EA requirement element is not currently being edited.\n\n" +
332
                        "Cancelling export - please retry once checks have been performed.", "Error");
333
 
334
                     cancelled = true;
335
                     return false;
336
                  }
337
 
338
                  // Attempt to set any attributes in the new ReqPro requirement. 
339
                  exportAttributes(rp_req, ea_req);
340
 
341
                  // Commit changes to ReqPro database
342
                  rp_req.Save();
343
 
344
                  // Now locate the new requirement under the selected package in ReqPro
345
                  if (rp_pkg != null)
346
                  {
347
                     rp_pkg.AddElement(rp_req, ReqPro40.enumPackageLookups.ePackageLookup_Object, ReqPro40.enumElementTypes.eElemType_Requirement);
348
                  }
349
 
350
                  // If the EA requirement has a parent requirement, then in ReqPro we must organise it such 
351
                  // that it has a parent-child hierarchical relationship
352
                  if (ea_req.ParentID != 0)
353
                  {
354
                     EA.Element parent_ea_req = Main.EA_Repository.GetElementByID(ea_req.ParentID);
355
                     if (parent_ea_req != null)
356
                     {
357
                        // get GUID of ReqPro parent requirement
358
                        string parent_guid = EA_TaggedValues.Read(parent_ea_req, Constants.TAG_GUID);
359
                        if (parent_guid != null && parent_guid.Length > 0 && parent_guid.StartsWith("{"))
360
                        {
361
                           // Get the parent ReqPro requirement
362
                           ReqPro40.Requirement parent_rp_req = ReqProDatabase.get_requirement_by_guid(parent_guid);
363
                           if (parent_rp_req != null)
364
                           {
365
                              // Establish relationship in ReqPro
366
                              rp_req.AssignParent(parent_rp_req, ReqPro40.enumRequirementLookups.eReqLookup_Object);
367
 
368
                              // Even though in EA, a parent-child relationship exists, we want to re-enforce that
369
                              // with a connection relationship too, so that when the parent and child exists on
370
                              // a diagram, they are shown linked together.
371
                              EA_Utilities.add_connection(parent_ea_req, ea_req);
372
                           }
373
                        }
374
                     }
375
                  }
376
 
377
                  // Now re-acquire the tag, which should no longer be in a pending form but have a real number
378
                  // assigned to it as a result of the commit we just did above.
379
                  rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
380
 
381
                  // Update the EA requirement for the second time, now with the correct and final tag
382
                  ea_req.Name = rp_req_tag + " " + ea_req_untagged_name;
383
                  ea_req.Update();
384
                  Main.WriteOutput("   (Re)Assigned Tag : " + ea_req.Name, ea_req.ElementID);
385
 
386
                  // Record the GUID and tag in EA tagged values. This will effectively bind the EA requirement
387
                  // to its new ReqPro requirement counterpart.
388
                  EA_TaggedValues.Write(ea_req, Constants.TAG_GUID, rp_req.GUID);
389
                  EA_TaggedValues.Write(ea_req, Constants.TAG_TAG, rp_req_tag);
390
 
391
                  // Save in the list of ReqPro GUIDs to support ReqPro orphaned requirement detection later on
392
                  ea_mastered_reqs_rp_guids.Add(rp_req.GUID);
393
 
394
                  // mark the requirement as having been created in EA.
395
                  EA_TaggedValues.Write(ea_req, Constants.TAG_CREATED_IN_EA, true);
396
 
397
                  // Update the ReqPro collection.
398
                  req_collection.Save();
399
               }
400
            }
401
 
402
            // Save details of the ReqPro package where the requirements were exported to. This info can be
403
            // used on the next export to auto-select the ReqPro destination package for the export, etc.
404
            if (rp_pkg != null)
405
            {
406
               EA_TaggedValues.Write(base.RQ_Element, Constants.TAG_LAST_EXPORT_GUID, rp_pkg.GUID);
407
               EA_TaggedValues.Write(base.RQ_Element, Constants.TAG_LAST_EXPORT_NAME, rp_pkg.Name);
408
            }
409
            else
410
            {
411
               // export occurred to the root package.
412
               EA_TaggedValues.Delete(base.RQ_Element, Constants.TAG_LAST_EXPORT_GUID);
413
               EA_TaggedValues.Delete(base.RQ_Element, Constants.TAG_LAST_EXPORT_NAME);
414
            }
415
         }
416
         else
417
         {
418
            Main.WriteOutput("Found no new requirements to add to ReqPro",-1);
419
         }
420
 
421
         Main.WriteSeperator();
422
         return true;
423
      }
424
 
425
 
426
      /// <summary>
427
      /// Updates ReqPro requirements that have masters in EA
428
      /// </summary>
429
      /// <param name="ea_mastered_reqs"></param>
430
      /// <param name="cancelled"></param>
431
      /// <returns></returns>
432
      private bool update_old_EA_mastered_requirements(ref ArrayList ea_mastered_reqs, 
433
         out bool cancelled)
434
      {
435
         cancelled = false;
436
 
437
         // if there are any EA mastered requirements...
438
         if (ea_mastered_reqs.Count > 0)
439
         {
440
            bool possibleOrphans = false;
441
 
442
            Main.WriteOutput(string.Format("Found {0} Requirements to update.", ea_mastered_reqs.Count), -1);
443
 
444
            ReqPro40.Requirements req_collection = ReqProDatabase.get_requirements();
445
 
446
            // process each EA mastered requirement
447
            int i_ea_mastered_reqs = 0;
448
            for (i_ea_mastered_reqs = 0; i_ea_mastered_reqs < ea_mastered_reqs.Count; ) // NOTE: no count increment done here
449
            {
450
               EA.Element ea_req = (EA.Element)ea_mastered_reqs[i_ea_mastered_reqs];
451
 
452
               // make sure there is a GUID
453
               string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID);
454
               if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
455
               {
456
                  ReqPro40.Requirement rp_req;
457
 
458
                  // Try and find the requirement in ReqPro
459
                  rp_req = ReqProDatabase.get_requirement_by_guid(GUID);
460
                  if (rp_req != null)
461
                  {
462
                     // copy name and notes from EA to ReqPro
463
                     string ea_req_untagged_name = untaggedReqName(ea_req.Name, true);
464
 
465
                     // Test that the EA requirement can be updated.
466
                     ea_req.Name = ea_req_untagged_name;
467
                     ea_req.Update();
468
                     if (false == ea_req.Update())
469
                     {
470
                        MessageBoxEx.Show(
471
                           "Failed to update EA requirement element.\n" +
472
                           "Check that the EA model is writeable.\n" +
473
                           "Check that the EA model is not locked by another user.\n" +
474
                           "Check that the EA requirement element is not currently being edited.\n\n" +
475
                           "Cancelling export - please retry once checks have been performed.", "Error");
476
 
477
                        cancelled = true;
478
                        return false;
479
                     }
480
 
481
                     // copy content to the existing ReqPro requirement
482
                     rp_req.Name = ea_req_untagged_name;
483
                     rp_req.Text = ea_req.Notes;
484
 
485
                     // Attempt to set any attributes in the existing ReqPro requirement. 
486
                     exportAttributes(rp_req, ea_req);
487
 
488
                     // Commit changes to ReqPro database
489
                     rp_req.Save();
490
 
491
                     // Although we are allowing EA to be the master repository of requirements
492
                     // if they were originally created in EA, we still want to use ReqPro as the
493
                     // master for any numbering scheme (ie. tags), so update the EA requirements
494
                     // Tag as necessary.
495
                     string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
496
                     ea_req.Name = rp_req_tag + " " + ea_req_untagged_name;
497
                     ea_req.Update();
498
                     EA_TaggedValues.Write(ea_req, Constants.TAG_TAG, rp_req_tag);
499
                     Main.WriteOutput("Updated : " + ea_req.Name, ea_req.ElementID);
500
                  }
501
                  else
502
                  {
503
                     possibleOrphans = true;
504
                     Main.WriteOutput("Warning, failed to find ReqPro requirement counterpart (possible orphan?)", ea_req.ElementID);
505
                  }
506
                  i_ea_mastered_reqs++;
507
               }
508
               else
509
               {
510
                  ea_mastered_reqs.RemoveAt(i_ea_mastered_reqs);
511
                  // do not increment i_ea_mastered_reqs after here
512
               }
513
            }
514
 
515
            Main.WriteSeperator();
516
 
517
            if (possibleOrphans == true)
518
            {
519
               Main.WriteOutput("", -1);
520
               Main.WriteOutput("One or more possible orphans have been found", -1);
521
               Main.WriteOutput("This could be the result of someone accidentally deleting the requirement", -1);
522
               Main.WriteOutput("in the ReqPro database. Or, it could be that someone modified the GUID tagged", -1);
523
               Main.WriteOutput("value in EA or ReqPro (very naughty).",-1);
524
               Main.WriteOutput("", -1);
525
               Main.WriteOutput("Going forward, if the requirement must be retained, delete all of its tagged values,", -1);
526
               Main.WriteOutput("in EA, remove the tag from its name, and attempt another export. The EA requirement will", -1);
527
               Main.WriteOutput("be given a new tag number, but at least it will re-appear in the ReqPro database.", -1);
528
               Main.WriteOutput("", -1);
529
               Main.WriteOutput("If the requirement is no longer needed, it can be deleted from EA once any design", -1);
530
               Main.WriteOutput("impacts are understood.", -1);
531
               Main.WriteSeperator();
532
            }
533
         }
534
         else
535
         {
536
            Main.WriteOutput("No ReqPro requirements need updating from their EA masters.",-1);
537
            Main.WriteSeperator();
538
         }
539
         return true;
540
      }
541
 
542
 
543
      /// <summary>
544
      /// Export relationships for the new requirements exported from EA
545
      /// </summary>
546
      /// <param name="ea_reqs"></param>
547
      private void export_new_EA_mastered_requirement_relationships(ref ArrayList ea_reqs)
548
      {
549
         // Algorithm design:
550
         //
551
         // for each new EA requirement (EA.Req) exported
552
         //   Get the ReqPro equivalent requirement (RP.Req)
553
         //   for each connector (EA.C) in EA.Req
554
         //      get referenced requirement (EA.RefReq) from EA.C
555
         //      find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro
556
         //      Establish a traces to relationship from RP.RefReq to RP.Req
557
 
558
         Main.WriteOutput("Creating Trace Relationships",-1);
559
 
560
         // for each new EA requirement (EA.Req) exported
561
         foreach (EA.Element ea_req in ea_reqs)
562
         {
563
            Main.WriteOutput("   " + ea_req.Name, ea_req.ElementID);
564
 
565
            string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID, "");
566
            if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
567
            {
568
               // Get the ReqPro equivalent requirement (RP.Req)
569
               ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(GUID);
570
               if (rp_req != null)
571
               {
572
                  // for each connector (EA.C) in EA.Req
573
                  foreach(EA.Connector ea_c in ea_req.Connectors)
574
                  {
575
                     int destId = -1;
576
 
577
                     // we dont care about direction of relationship, so test for both
578
                     if (ea_c.ClientID == ea_req.ElementID)
579
                        destId = ea_c.SupplierID;
580
                     else if (ea_c.SupplierID == ea_req.ElementID)
581
                        destId = ea_c.ClientID;
582
 
583
                     // and make sure we filter out self-referential connectors
584
                     if (destId != ea_req.ElementID)
585
                     {
586
                        // get referenced requirement (EA.RefReq) from EA.C
587
                        EA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);
588
                        if (ea_ref_req != null && ea_ref_req.Type.Equals("Requirement"))
589
                        {
590
                           // Get the GUID from the referenced element
591
                           GUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");
592
                           if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
593
                           {
594
                              // find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro
595
                              ReqPro40.Requirement rp_ref_req = ReqProDatabase.get_requirement_by_guid(GUID);
596
                              if (rp_ref_req != null)
597
                              {
598
                                 // Establish a traces to relationship from RP.RefReq to RP.Req
599
                                 ReqPro40.Relationships rp_ref_req_c = (ReqPro40.Relationships)rp_ref_req.TracesTo;
600
                                 if (rp_ref_req_c != null)
601
                                 {
602
                                    // wrap the relationship add in exception handling - In EA, a parent child relationship
603
                                    // can exist by virtue of the elements parentID values, and such does not prevent the
604
                                    // existence of a connection relationship either. But in ReqPro, it does. Once a requirement
605
                                    // has a "hierarchical" relationship, you cannot establish the same relationship in a 2nd
606
                                    // way, using for example a TracesTo relationship. Using exception handling here is probably
607
                                    // quicker than trying to examine what relationships already exist and act accordingly.
608
                                    try
609
                                    {
610
                                       ReqPro40.Relationship rp_ref_req_rel = 
611
                                          rp_ref_req_c.Add(rp_req,
612
                                          ReqPro40.enumRequirementLookups.eReqLookup_Object,
613
                                          null, ReqPro40.enumRelatedProjectLookups.eRelProjLookup_Empty,
614
                                          false);
615
                                       if (rp_ref_req_rel != null)
616
                                       {
617
                                          // commit
618
                                          rp_ref_req.Save();
619
                                       }
620
                                    }
621
                                    catch
622
                                    {
623
                                    }
624
                                 }
625
                              }
626
                           }
627
                        }
628
                     }
629
                  }
630
               }
631
            }
632
         }
633
         Main.WriteSeperator();
634
      }
635
 
636
 
637
      /// <summary>
638
      /// Update ReqPro relationships for requirements mastered in EA
639
      /// </summary>
640
      /// <param name="ea_mastered_reqs"></param>
641
      private void update_old_EA_mastered_requirement_relationships(ref ArrayList ea_mastered_reqs)
642
      {
643
         // Algorithm design:
644
         //
645
         //   for each EA requirement (EA.Req) updated
646
         //     Get the ReqPro equivalent requirement (RP.Req)
647
         //     for each connector (EA.C) in EA.Req
648
         //       get referenced requirement (EA.RefReq) from EA.C
649
         //       find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro
650
         //       Establish a traces to relationship from RP.RefReq to RP.Req (if it does not already exist)
651
         //       
652
         //     for each trace-to relationship (RP.C) in RP.Req
653
         //       if relationship does not exist in EA.Req
654
         //         delete RP.C
655
         //
656
         //     for each trace-from relationship (RP.C) in RP.Req
657
         //       if relationship does not exist in EA.Req
658
         //         delete RP.C
659
         //
660
 
661
         Main.WriteOutput("Updating Trace Relationships",-1);
662
 
663
         // for each EA requirement (EA.Req) updated
664
         foreach(EA.Element ea_req in ea_mastered_reqs)
665
         {
666
            Main.WriteOutput("   " + ea_req.Name, ea_req.ElementID);
667
 
668
            string GUID = EA_TaggedValues.Read(ea_req, Constants.TAG_GUID, "");
669
            if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
670
            {
671
               // Get the ReqPro equivalent requirement (RP.Req)
672
               ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(GUID);
673
               if (rp_req != null)
674
               {
675
                  // for each connector (EA.C) in EA.Req
676
                  foreach(EA.Connector ea_c in ea_req.Connectors)
677
                  {
678
                     int destId = -1;
679
 
680
                     // we dont care about direction of relationship, so test for both
681
                     if (ea_c.ClientID == ea_req.ElementID)
682
                        destId = ea_c.SupplierID;
683
                     else if (ea_c.SupplierID == ea_req.ElementID)
684
                        destId = ea_c.ClientID;
685
 
686
                     // and make sure we filter out self-referential connectors
687
                     if (destId != ea_req.ElementID)
688
                     {
689
                        // get referenced requirement (EA.RefReq) from EA.C
690
                        EA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);
691
                        if (ea_ref_req != null && ea_ref_req.Type.Equals("Requirement"))
692
                        {
693
                           // Get the GUID from the referenced element
694
                           GUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");
695
                           if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
696
                           {
697
                              // find EA.RefReq's equivalent requirement (RP.RefReq) in ReqPro
698
                              ReqPro40.Requirement rp_ref_req = ReqProDatabase.get_requirement_by_guid(GUID);
699
                              if (rp_ref_req != null)
700
                              {
701
                                 // Establish a traces to relationship from RP.RefReq to RP.Req (if it does not already exist)
702
                                 ReqPro40.Relationships rp_ref_req_c = (ReqPro40.Relationships)rp_ref_req.TracesTo;
703
                                 if (rp_ref_req_c != null)
704
                                 {
705
                                    // ReqPro throws an exception if you try to create a relationship that already exists.
706
                                    // ReqPro doesn't seem to give any easy way to ask the question, "does a relationship
707
                                    // exist between A and B". It is debatable whether running a hand written function to 
708
                                    // answer the question is going to be any quicker than just catching the exceptions 
709
                                    // and ignoring them. For now though, use exception handling in this very bad way.
710
                                    try
711
                                    {
712
                                       ReqPro40.Relationship rp_ref_req_rel = 
713
                                          rp_ref_req_c.Add(rp_req,
714
                                          ReqPro40.enumRequirementLookups.eReqLookup_Object,
715
                                          null, ReqPro40.enumRelatedProjectLookups.eRelProjLookup_Empty,
716
                                          false);
717
                                       if (rp_ref_req_rel != null)
718
                                       {
719
 
720
                                          // commit
721
                                          rp_ref_req.Save();
722
 
723
                                          Main.WriteOutput("      Created Trace Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);
724
                                       }
725
                                    }
726
                                    catch
727
                                    {
728
                                       // do nothing
729
                                    }
730
                                 }
731
                              }
732
                           }
733
                        }
734
                     }
735
                  }
736
 
737
                  // Examine the Traces-To relationships in ReqPro
738
                  int limit_numberOfTraceTo = 0;
739
                  if (true == rp_req.get_HasTracesTo(ref limit_numberOfTraceTo))
740
                  {
741
                     ReqPro40.Relationships rp_req_c = (ReqPro40.Relationships)rp_req.TracesTo;
742
                     if (rp_req_c != null)
743
                     {
744
                        // for each relationship (RP.C) in RP.Req
745
                        rp_req_c.MoveFirst();
746
                        int i_numberOfTraceTo;
747
                        for (i_numberOfTraceTo = 0; i_numberOfTraceTo < limit_numberOfTraceTo; i_numberOfTraceTo++)
748
                        {
749
                           // Obtain the sub-requirement from the relationship, and parse it
750
                           ReqPro40.Relationship rp_req_rel = rp_req_c.GetCurrentRelationship();
751
 
752
                           ReqPro40.Requirement rp_ref_req = 
753
                              rp_req_rel.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
754
 
755
                           if (rp_ref_req != null)
756
                           {
757
                              // if relationship does not exist in EA.Req
758
                              if (!ea_element_traces_to_or_from(ea_req, rp_ref_req.GUID))
759
                              {
760
                                 // delete RP.C
761
                                 rp_req_rel.Delete();
762
                                 Main.WriteOutput("      Deleted Trace-To Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);
763
                              }
764
                           }
765
 
766
                           rp_req_c.MoveNext();
767
                        }
768
                        // commit
769
                        rp_req.Save();
770
                     }
771
                  }
772
 
773
                  // Examine the Traces-From relationships in ReqPro
774
                  int limit_numberOfTraceFrom = 0;
775
                  if (true == rp_req.get_HasTracesFrom(ref limit_numberOfTraceFrom))
776
                  {
777
                     ReqPro40.Relationships rp_req_c = (ReqPro40.Relationships)rp_req.TracesFrom;
778
                     if (rp_req_c != null)
779
                     {
780
                        // for each relationship (RP.C) in RP.Req
781
                        rp_req_c.MoveFirst();
782
                        int i_numberOfTraceFrom;
783
                        for (i_numberOfTraceFrom = 0; i_numberOfTraceFrom < limit_numberOfTraceFrom; i_numberOfTraceFrom++)
784
                        {
785
                           // Obtain the sub-requirement from the relationship, and parse it
786
                           ReqPro40.Relationship rp_req_rel = rp_req_c.GetCurrentRelationship();
787
 
788
                           ReqPro40.Requirement rp_ref_req = 
789
                              rp_req_rel.get_SourceRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
790
 
791
                           if (rp_ref_req != null)
792
                           {
793
                              // if relationship does not exist in EA.Req
794
                              if (!ea_element_traces_to_or_from(ea_req, rp_ref_req.GUID))
795
                              {
796
                                 // delete RP.C
797
                                 rp_req_rel.Delete();
798
                                 Main.WriteOutput("      Deleted Trace-From Relationship to " + rp_ref_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag), -1);
799
                              }
800
                           }
801
 
802
                           rp_req_c.MoveNext();
803
                        }
804
                        // commit
805
                        rp_req.Save();
806
                     }
807
                  }
808
               }
809
            }
810
         }
811
         Main.WriteSeperator();
812
      }
813
 
814
 
815
      /// <summary>
816
      /// Use historical data stored in the ReqProDB element to 
817
      /// </summary>
818
      /// <param name="ea_mastered_reqs_rp_guids"></param>
819
      private void report_orphaned_ReqPro_requirements(ref ArrayList ea_mastered_reqs_rp_guids)
820
      {
821
         // we can only report on EA mastered requirements that have been deleted, if the extent of
822
         // the export is total, not partial
823
         if (m_ExportExtent == ExportForm.ExportExtent.REQPRODB_REQS)
824
         {
825
            // Get the last list of EA mastered requirements from the ReqProDB element
826
            if (base.RQ_Element.Notes != null && base.RQ_Element.Notes.Length > 0)
827
            {
828
               // split it into a string array
829
               char [] seperators = {'\r','\n'};
830
               string [] options = base.RQ_Element.Notes.Split(seperators);
831
 
832
               ArrayList rp_orphaned_reqs = new ArrayList();
833
               ArrayList rp_non_orphaned_reqs = new ArrayList();
834
 
835
               // process the string array to accumulate list of orphaned and non-orphaned requirements
836
               foreach (string s in options)
837
               {
838
                  string trimmed_s = s.Trim();
839
                  if (trimmed_s.Length > 0)
840
                  {
841
                     if (trimmed_s.StartsWith(Constants.KEY_EXPORTED_GUID))
842
                     {
843
                        string value = trimmed_s.Substring(Constants.KEY_EXPORTED_GUID.Length);
844
                        if (false == ea_mastered_reqs_rp_guids.Contains(value))
845
                        {
846
                           rp_orphaned_reqs.Add(value);
847
                        }
848
                        else
849
                        {
850
                           rp_non_orphaned_reqs.Add(value);
851
                        }
852
                     }
853
                  }
854
               }
855
 
856
               // default decision to use when constructing export options for ReqProDB element later on
857
               DialogResult dlgRes = DialogResult.No;
858
 
859
               // report on orphaned requirements
860
               if (rp_orphaned_reqs.Count > 0)
861
               {
862
                  ArrayList rp_orphaned_req_strings = new ArrayList();
863
 
864
                  foreach(string s in rp_orphaned_reqs)
865
                  {
866
                     ReqPro40.Requirement rp_req = ReqProDatabase.get_requirement_by_guid(s);
867
                     if (rp_req != null)
868
                     {
869
                        string rp_req_tag = rp_req.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
870
                        if (rp_req_tag != null)
871
                        {
872
                           rp_orphaned_req_strings.Add("   " + rp_req_tag + " " + rp_req.Name);
873
                        }
874
                     }
875
                  }
876
 
877
                  if (rp_orphaned_req_strings.Count > 0)
878
                  {
879
                     Main.WriteOutput("The following EA Mastered requirements in ReqPro, may no longer be needed.", -1);
880
                     Main.WriteOutput("i.e. they are orphaned requirements in ReqPro, because they have been deleted", -1);
881
                     Main.WriteOutput("in EA since the last export.", -1);
882
                     Main.WriteOutput("Please verify and if necessary, mark them as obsolete in ReqPro.", -1);
883
 
884
                     foreach(string s in rp_orphaned_req_strings)
885
                     {
886
                        Main.WriteOutput(s, -1);
887
                     }
888
 
889
                     Main.WriteSeperator();
890
 
891
                     // allow user to specifiy whether we should forget about the orphaned requirements
892
                     // the next time we do an export.
893
                     dlgRes = MessageBoxEx.Show(
894
                        "Some ReqPro requirements have been orphaned (see output\n" +
895
                        "tab display for more information).\n" + 
896
                        "Ignore these problems in future exports?", "Confirm", MessageBoxButtons.YesNo);
897
                  }
898
               }
899
 
900
               StringBuilder sb = new StringBuilder();
901
 
902
               // reconstruct non-export related options using the appropriate ReqProFilterForm static method
903
               // That method keeps knowledge of the import filter options localised in the right place.
904
               ReqProFilterForm.saveFilterSettings(options, ref sb);
905
 
906
               // If this export had nothing to work with from the ReqProDB options....
907
               if (rp_orphaned_reqs.Count == 0 && rp_non_orphaned_reqs.Count == 0)
908
               {
909
                  // The options did not contain any key values. That probably means that up till now,
910
                  // any export that has been performed previously, did not actually export anything.
911
                  // So, just add whatever we exported this time (if anything)
912
                  if (ea_mastered_reqs_rp_guids.Count > 0)
913
                  {
914
                     sb.Append(Constants.EXPORT_HEADING);
915
                     foreach (string s in ea_mastered_reqs_rp_guids)
916
                     {
917
                        sb.Append(Constants.KEY_EXPORTED_GUID);
918
                        sb.Append(s);
919
                        sb.Append("\r\n");
920
                     }
921
                  }
922
               }
923
               else
924
               {
925
                  sb.Append(Constants.EXPORT_HEADING);
926
 
927
                  // construct export-related options
928
                  if (dlgRes == DialogResult.No)
929
                  {
930
                     foreach (string s in rp_orphaned_reqs)
931
                     {
932
                        sb.Append(Constants.KEY_EXPORTED_GUID);
933
                        sb.Append(s);
934
                        sb.Append("\r\n");
935
                     }
936
                  }
937
                  foreach (string s in rp_non_orphaned_reqs)
938
                  {
939
                     sb.Append(Constants.KEY_EXPORTED_GUID);
940
                     sb.Append(s);
941
                     sb.Append("\r\n");
942
 
943
                     // if this item is in ea_mastered_reqs_rp_guids, then remove it from there so that we do not
944
                     // duplicate it in the options string when we process ea_mastered_reqs_rp_guids after this loop
945
                     // completes
946
                     if (ea_mastered_reqs_rp_guids.Contains(s))
947
                     {
948
                        ea_mastered_reqs_rp_guids.Remove(s);
949
                     }
950
                  }
951
 
952
                  // If there are any items left in ea_mastered_reqs_rp_guids, add them too
953
                  foreach (string s in ea_mastered_reqs_rp_guids)
954
                  {
955
                     sb.Append(Constants.KEY_EXPORTED_GUID);
956
                     sb.Append(s);
957
                     sb.Append("\r\n");
958
                  }
959
               }
960
 
961
               base.RQ_Element.Notes = sb.ToString();
962
               base.RQ_Element.Update();
963
            }
964
         }
965
      }
966
 
967
 
968
      private bool ea_element_traces_to_or_from(EA.Element ea_req, string rp_GUID)
969
      {
970
         foreach(EA.Connector ea_c in ea_req.Connectors)
971
         {
972
            int destId = -1;
973
 
974
            // we dont care about direction of relationship, so test for both
975
            if (ea_c.ClientID == ea_req.ElementID)
976
               destId = ea_c.SupplierID;
977
            else if (ea_c.SupplierID == ea_req.ElementID)
978
               destId = ea_c.ClientID;
979
 
980
            // and make sure we filter out self-referential connectors
981
            if (destId != ea_req.ElementID)
982
            {
983
               EA.Element ea_ref_req = Main.EA_Repository.GetElementByID(destId);
984
               if (ea_ref_req != null)
985
               {
986
                  string GUID = EA_TaggedValues.Read(ea_ref_req, Constants.TAG_GUID, "");
987
                  if (GUID != null && GUID.Length > 0 && GUID.StartsWith("{"))
988
                  {
989
                     if (rp_GUID.Equals(GUID))
990
                        return true;
991
                  }
992
               }
993
            }
994
         }
995
 
996
         return false;
997
      }
998
 
999
 
1000
      /// <summary>
1001
      /// Look for and strip any temporary tag from the requirement name, returning a new
1002
      /// string to be used as the requirement name
1003
      /// </summary>
1004
      /// <param name="taggedReqName"></param>
1005
      /// <returns></returns>
1006
      private string untaggedReqName(string taggedReqName, bool force)
1007
      {
1008
         if (taggedReqName != null)
1009
         {
1010
            // Try and split the string into two tokens at the first space character
1011
            char [] delim = {' '};
1012
            string [] tokens = taggedReqName.Split(delim, 2);
1013
 
1014
            // if there are two tokens resulting from the split
1015
            if (tokens.GetLength(0) == 2)
1016
            {
1017
 
1018
               // if the first token appears to be a tag
1019
               if (force == true
1020
                  || tokens[0].StartsWith("REQ")
1021
                  || tokens[0].StartsWith("TAG")
1022
                  || tokens[0].StartsWith("SPR")
1023
                  || (tokens[0].IndexOfAny(numbers) > 0 && tokens[0].IndexOfAny(letters) == 0))
1024
               {
1025
                  // return the token after the tag.
1026
                  return tokens[1];
1027
               }
1028
            }
1029
         }
1030
         // default to the input string
1031
         return taggedReqName;
1032
      }
1033
 
1034
 
1035
      private void exportAttributes(ReqPro40.Requirement rp_req, EA.Element ea_req)
1036
      {
1037
         // Update the attributes of a ReqPro requirement. We have to be very careful here.
1038
         // ReqPro does not like us trying to set the value of attributes that do not exist for the
1039
         // specified requirement type, and it also does not like us trying to set an attribute that is
1040
         // a list type, to a value that is not in the predefined set of values for the list type.
1041
         bool hasStatus = false;
1042
         bool hasDifficulty = false;
1043
         bool hasPriority = false;
1044
         bool hasSource = false;
1045
         bool hasSourceVersion = false;
1046
         bool hasSourceSection = false;
1047
         bool hasSubsystem = false;
1048
         bool hasStability = false;
1049
         bool hasType = false;
1050
 
1051
         // Use the ReqProParser's knowledge of requirement types and attribute type associations to tell
1052
         // us what attributes we can set, and then use the setListItemValue() function to do the setting.
1053
         // That function knows how to set List items correctly and safely so as to not cause exceptions
1054
         // to be raised in the ReqPro automation onject.
1055
         if (reqTypeHasOneOrMoreAttrs(this.m_ReqType,
1056
            ref hasStatus, ref hasDifficulty, ref hasPriority,
1057
            ref hasSource, ref hasSourceVersion, ref hasSourceSection,
1058
            ref hasSubsystem, ref hasStability, ref hasType))
1059
         {
1060
            if (hasStatus)
1061
            {
1062
               setListItemAttrValue(rp_req, "Status", ea_req.Status);
1063
            }
1064
            if (hasDifficulty)
1065
            {
1066
               setListItemAttrValue(rp_req, "Difficulty", ea_req.Difficulty);
1067
            }
1068
            if (hasPriority)
1069
            {
1070
               setListItemAttrValue(rp_req, "Priority", ea_req.Priority);
1071
            }
1072
         }
1073
      }
1074
 
1075
 
1076
      /// <summary>
1077
      /// Set a ReqPro requirement attribute value, for an attribute that is a list type.
1078
      /// This function only allows the setting of the value, if it is one of the values
1079
      /// allowed for the list item. This ensures we do not get an exception raised in the
1080
      /// ReqPro automation object.
1081
      /// </summary>
1082
      /// <param name="rp_req"></param>
1083
      /// <param name="label"></param>
1084
      /// <param name="value"></param>
1085
      private void setListItemAttrValue(ReqPro40.Requirement rp_req, string label, string value)
1086
      {
1087
         // look through each attribute value, for the one whose label matches the one specified
1088
         ReqPro40.AttrValues rp_attr_values = rp_req.AttrValues;
1089
 
1090
         foreach (ReqPro40.AttrValue rp_attr_value in rp_attr_values)
1091
         {
1092
            if (rp_attr_value != null && rp_attr_value.Label.Equals(label))
1093
            {
1094
               // Look through each list item value to make sure that one exists that matches
1095
               // the value specified
1096
               ReqPro40.ListItemValues rp_list_item_values = rp_attr_value.ListItemValues;
1097
               if (rp_list_item_values != null)
1098
               {
1099
                  foreach (ReqPro40.ListItemValue rp_list_item_value in rp_list_item_values)
1100
                  {
1101
                     if (rp_list_item_value.Text.Equals(value))
1102
                     {
1103
                        // We found that the list contains the value specified, so set the value of the attribute
1104
                        rp_list_item_value.Selected = true;
1105
 
1106
                        // exit inner loop
1107
                        break;
1108
                     }
1109
                  }
1110
               }
1111
               // exit outer loop
1112
               break;
1113
            }
1114
         }
1115
      }
1116
 
1117
 
1118
	}
1119
}