1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11 
12 
13 
14 
15 #include <stdlib.h>
16 
17 #include "DXStrings.h"
18 #include "lex.h"
19 #include "ProcessGroupManager.h"
20 #include "ProcessGroupAssignDialog.h"
21 #include "Dictionary.h"
22 #include "ListIterator.h"
23 #include "List.h"
24 #include "Network.h"
25 #include "ErrorDialogManager.h"
26 #include "EditorWindow.h"
27 #include "DXPacketIF.h"
28 #include "DXApplication.h"
29 
ProcessGroupManager(Network * net)30 ProcessGroupManager::ProcessGroupManager(Network *net):
31     GroupManager(net, theSymbolManager->registerSymbol(PROCESS_GROUP))
32 {
33     // Would like to assert this, but in Network::Network, theDXApplication->network
34     // isn't set yet.
35     //ASSERT (theDXApplication->network == net);
36     this->assignment = NULL;
37 }
~ProcessGroupManager()38 ProcessGroupManager::~ProcessGroupManager()
39 {
40 }
41 
clear()42 void ProcessGroupManager::clear()
43 {
44     this->GroupManager::clear();
45     this->clearArgument();
46 
47     if(this->assignment)
48     {
49         this->sendAssignment(DETACH);
50 	this->clearAssignment();
51     }
52 
53     if(theDXApplication->processGroupAssignDialog)
54 	theDXApplication->processGroupAssignDialog->unmanage();
55 }
56 
getGroupHost(int n)57 const char* ProcessGroupManager::getGroupHost(int n)
58 {
59     return this->getGroupHost(this->getGroupName(n));
60 }
61 
getGroupHost(const char * name)62 const char* ProcessGroupManager::getGroupHost(const char *name)
63 {
64     ProcessGroupRecord *record
65     	= (ProcessGroupRecord*)this->groups.findDefinition(name);
66 
67     if(NOT record)
68 	return NULL;
69     else
70 	return record->host;
71 }
72 
getGroupNewHost(int n)73 const char* ProcessGroupManager::getGroupNewHost(int n)
74 {
75     return this->getGroupNewHost(this->getGroupName(n));
76 }
77 
getGroupNewHost(const char * name)78 const char* ProcessGroupManager::getGroupNewHost(const char *name)
79 {
80     ProcessGroupRecord *record
81     	= (ProcessGroupRecord*)this->groups.findDefinition(name);
82 
83     if(NOT record)
84 	return NULL;
85     else
86 	return record->newhost;
87 }
88 
getGroupHostDirty(const char * name)89 boolean ProcessGroupManager::getGroupHostDirty(const char *name)
90 {
91     ProcessGroupRecord *record
92     	= (ProcessGroupRecord*)this->groups.findDefinition(name);
93 
94     if(NOT record)
95 	return FALSE;
96     else
97 	return record->isDirty();
98 }
99 
clearGroupHostDirty(const char * name)100 void ProcessGroupManager::clearGroupHostDirty(const char *name)
101 {
102     ProcessGroupRecord *record
103     	= (ProcessGroupRecord*)this->groups.findDefinition(name);
104 
105     if(record)
106 	record->setDirty(FALSE);
107 }
108 
assignHost(int n,const char * hostname)109 boolean ProcessGroupManager::assignHost(int n, const char *hostname)
110 {
111     return assignHost(this->getGroupName(n), hostname);
112 }
113 
assignHost(const char * groupname,const char * hostname)114 boolean ProcessGroupManager::assignHost(const char *groupname,
115                                       const char *hostname)
116 {
117     ProcessGroupRecord *record
118         = (ProcessGroupRecord*)this->groups.findDefinition(groupname);
119 
120     if(NOT record)
121         return FALSE;
122 
123     if(record->newhost)
124          delete record->newhost;
125 
126     if(hostname)
127         record->newhost = DuplicateString(hostname);
128     else
129         record->newhost = DuplicateString("localhost");
130 
131     return TRUE;
132 }
133 
updateHosts()134 void ProcessGroupManager::updateHosts()
135 {
136     int  i;
137     const char *group;
138     ProcessGroupRecord *record;
139 
140     for(i = 1; i <= this->getGroupCount(); i++)
141     {
142         group = this->getGroupName(i);
143         record = (ProcessGroupRecord*)this->groups.findDefinition(group);
144 
145         if (!record OR !record->newhost)  continue;
146 
147 	if (!record->host || !EqualString(record->host, record->newhost)) {
148 	    if(record->host)
149 		 delete record->host;
150 
151 	    record->host = DuplicateString(record->newhost);
152 	    record->setDirty(TRUE);
153 	    record->getNetwork()->setFileDirty();
154 	}
155         delete record->newhost;
156         record->newhost = NULL;
157     }
158 }
159 
clearNewHosts()160 void ProcessGroupManager::clearNewHosts()
161 {
162     int  i;
163     const char *group;
164     ProcessGroupRecord *record;
165 
166     for(i = 1; i <= this->getGroupCount(); i++)
167     {
168         group = this->getGroupName(i);
169         record = (ProcessGroupRecord*)this->groups.findDefinition(group);
170 
171         if (!record OR !record->newhost)  continue;
172 
173         delete record->newhost;
174         record->newhost = NULL;
175     }
176 }
177 
getArgument(const char * name)178 const char* ProcessGroupManager::getArgument(const char *name)
179 {
180     ProcessHostRecord *record =
181                 (ProcessHostRecord*)this->arguments.findDefinition(name);
182     if(record)
183     	return record->args;
184     else
185 	return NUL(char*);
186 }
187 
getArgumentDirty(const char * name)188 boolean ProcessGroupManager::getArgumentDirty(const char *name)
189 {
190     ProcessHostRecord *record =
191                 (ProcessHostRecord*)this->arguments.findDefinition(name);
192 
193     if(record)
194     	return record->dirty;
195     else
196 	return FALSE;
197 }
198 
clearArgumentDirty(const char * name)199 void ProcessGroupManager::clearArgumentDirty(const char *name)
200 {
201     ProcessHostRecord *record =
202                 (ProcessHostRecord*)this->arguments.findDefinition(name);
203 
204     if(record)
205     	record->dirty = FALSE;
206 }
207 
assignArgument(const char * host,const char * args)208 void  ProcessGroupManager::assignArgument(const char *host,const char *args)
209 {
210     ProcessHostRecord *record =
211 		(ProcessHostRecord*)this->arguments.findDefinition(host);
212 
213     if (record)
214     {
215 	if(record->args)
216 		delete record->args;
217 	if(args)
218 	    record->args = DuplicateString(args);
219 	else
220 	    record->args = NUL(char*);
221     }
222     else
223     {
224     	record = new ProcessHostRecord((char*)args);
225     	this->arguments.addDefinition(host,(const void*)record);
226     }
227 
228     record->dirty = TRUE;
229     this->app->network->setFileDirty();
230 }
231 // clear the argument dictionary
clearArgument()232 void  ProcessGroupManager::clearArgument()
233 {
234     ProcessHostRecord *record;
235 
236     while ( (record = (ProcessHostRecord*) this->arguments.getDefinition(1)) )
237     {
238         this->arguments.removeDefinition((const void*)record);
239         delete record;
240     }
241 }
242 
243 
createAssignment()244 Dictionary *ProcessGroupManager::createAssignment()
245 {
246     int i, size = this->groups.getSize();
247 
248     if(size == 0)
249 	return NULL;
250 
251     Dictionary *dic = new Dictionary();
252     List *list;
253 
254     for (i=1; i<=size; i++)
255     {
256 	const char *host = this->getGroupHost(i);
257 	char *group;
258 	if(NOT host)
259 	    host = "localhost";
260 //	    continue;
261 
262 	group = DuplicateString((char*)this->groups.getStringKey(i));
263 
264 	if( (list = (List*)dic->findDefinition(host)) )
265         {
266 	    list->appendElement((void*)group);
267 	}
268 	else
269 	{
270 	    list = new List();
271 	    list->appendElement((void*)group);
272 	    dic->addDefinition(host, (void*)list);
273 	}
274     }
275 
276     if(dic->getSize())
277 	return dic;
278 
279     delete dic;
280     return NULL;
281 }
282 
clearAssignment()283 void ProcessGroupManager::clearAssignment()
284 {
285     if(NOT this->assignment)
286 	return;
287 
288     int i, size = this->assignment->getSize();
289     ListIterator li;
290     char *group;
291     List *list;
292 
293     for (i=1; i<=size; i++)
294     {
295 	list = (List*)this->assignment->getDefinition(i);
296 	li.setList(*list);
297 
298 	while( (group = (char*)li.getNext()) )
299 	     delete group;
300 
301 	list->clear();
302 	delete list;
303     }
304 
305     delete this->assignment;
306     this->assignment = NULL;
307 }
308 
sendAssignment(int function)309 void ProcessGroupManager::sendAssignment(int function)
310 {
311     DXPacketIF *p = this->app->getPacketIF();
312     if (!p)
313         return;
314 
315     this->setDirty(FALSE);
316     if (!this->assignment)
317         return;
318 
319     List *list;
320     ListIterator li;
321     int i;
322     boolean first;
323     char *func = NULL, *host, *grouplist,*group, *cmd;
324 
325 	switch(function)
326 	{
327 	   case ATTACH:
328 
329 		func = "group attach";
330 		this->dirty = FALSE;
331 		break;
332 
333 	   case DETACH:
334 
335 		func = "group detach";
336 		break;
337 
338 	   default:
339 
340 		ASSERT(FALSE);
341 	}
342 
343         for(i = 1; i <= this->assignment->getSize(); i++)
344         {
345             host = (char*)this->assignment->getStringKey(i);
346 	    this->clearArgumentDirty(host);
347 	    const char *args = this->getArgument(host);
348             list = (List*)this->assignment->getDefinition(i);
349 
350 	    /* figure out how much, and allocate space for all group names */
351 	    int grouplistSize = 0;
352 	    li.setList(*list);
353 	    while( (group = (char*)li.getNext()) )
354 		grouplistSize += STRLEN(group);
355 	    grouplist = new char[grouplistSize + 20 * list->getSize()];
356 	    grouplist[0] = '\0';
357 
358             first = TRUE;
359             li.setList(*list);
360 			while( (group = (char*)li.getNext()) )
361 			{
362 				this->clearGroupHostDirty(group);
363 				if(first)
364 					first = FALSE;
365 				else
366 					strcat(grouplist, ",");
367 
368 				if(function == DETACH)
369 					strcat(grouplist, "\"");
370 
371 				strcat(grouplist, group);
372 
373 				if(function == DETACH)
374 					strcat(grouplist, "\"");
375 			}
376 
377            cmd = new char[STRLEN("exective( ), ")
378                           + STRLEN(func)
379                           + STRLEN(host)
380                           + STRLEN(args)
381                           + STRLEN(grouplist) + 20];
382 
383 	   if(function == ATTACH)
384 	   {
385 	   	if(args)
386                     SPRINTF(cmd, "Executive(\"%s\",{\"%s: %s %s\"});\n",
387 				   	func,grouplist,host,args);
388 	   	else
389                     SPRINTF(cmd, "Executive(\"%s\",{\"%s: %s\"});\n",
390 				   	func,grouplist,host);
391 	   }
392 	   else
393 		SPRINTF(cmd, "Executive(\"%s\",{%s});\n",func,grouplist);
394 
395            p->send(PacketIF::FOREGROUND, cmd);
396     	   p->sendImmediate("sync");
397 
398            delete grouplist;
399            delete cmd;
400         }
401 
402 
403 }
404 
updateAssignment()405 void   ProcessGroupManager::updateAssignment()
406 {
407     DXPacketIF *p = this->app->getPacketIF();
408 
409     //
410     // If the assignment hasn't been sent, don't bother detaching.
411     //
412     if(this->isDirty() OR !this->assignment OR !p)
413     {
414 	this->clearAssignment();
415 	this->assignment = this->createAssignment();
416         if(p)
417             this->sendAssignment(ATTACH);
418         else
419             this->setDirty();
420 	return;
421     }
422 
423     List *list, *oldList;
424     ListIterator li, oldLi;
425     int i;
426     boolean first, argsDirty;
427     char *host, *grouplist,*group,*oldGroup, *cmd;
428 
429     //
430     // Detach groups that changed their assignment.
431     //
432     for(i = 1; i <= this->assignment->getSize(); i++)
433     {
434         host = (char*)this->assignment->getStringKey(i);
435 	list = (List*)this->assignment->getDefinition(i);
436 	argsDirty = this->getArgumentDirty(host);
437 
438         li.setList(*list);
439         while( (group = (char*)li.getNext()) )
440 	    if(argsDirty OR this->getGroupHostDirty(group))
441 		this->detachGroup(host,group);
442     }
443 
444     Dictionary *newAss = this->createAssignment();
445 
446     if(NOT newAss)
447     {
448 	this->clearAssignment();
449         this->setDirty();
450 	return;
451     }
452 
453     //
454     // Attach groups that changed their assignment.
455     //
456     for(i = 1; i <= newAss->getSize(); i++)
457     {
458         host = (char*)newAss->getStringKey(i);
459 	const char *args = this->getArgument(host);
460 	argsDirty = this->getArgumentDirty(host);
461         list = (List*)newAss->getDefinition(i);
462 
463 	/* figure out how much, and allocate space for all group names */
464 	int grouplistSize = 0;
465 	li.setList(*list);
466 	while( (group = (char*)li.getNext()) )
467 	    grouplistSize += STRLEN(group);
468 	grouplist = new char[grouplistSize + 20 * list->getSize()];
469 	grouplist[0] = '\0';
470 
471 
472 	this->clearArgumentDirty(host);
473 
474 	if(argsDirty)
475 	    oldList = NULL;
476 	else
477 	    oldList = (List*)this->assignment->findDefinition(host);
478 
479         first = TRUE;
480         li.setList(*list);
481         while( (group = (char*)li.getNext()) )
482 	{
483 	    if(oldList)
484 	    {
485 		oldLi.setList(*oldList);
486 		while( (oldGroup  = (char*)oldLi.getNext()) )
487 		    if(EqualString(oldGroup, group)
488 			AND NOT this->getGroupHostDirty(group))
489 			break;
490 
491 		if(oldGroup)
492 		    continue;
493 	    }
494 
495 	    this->clearGroupHostDirty(group);
496 
497             if(first)
498             {
499                  strcpy(grouplist, group);
500                  first = FALSE;
501             }
502             else
503             {
504                     strcat(grouplist, ",");
505                     strcat(grouplist, group);
506             }
507 	}
508 	if(NOT first)
509 	{
510             cmd = new char[STRLEN("exective( group attach ), ")
511                           + STRLEN(host)
512                           + STRLEN(args)
513                           + STRLEN(grouplist) + 20];
514 
515 	   if(args)
516                SPRINTF(cmd, "Executive(\"group attach\",{\"%s: %s %s\"});\n",
517 				   	grouplist,host,args);
518 	   else
519                SPRINTF(cmd, "Executive(\"group attach\",{\"%s: %s\"});\n",
520 				   	grouplist,host);
521 
522             p->send(PacketIF::FOREGROUND, cmd);
523     	    p->sendImmediate("sync");
524             delete cmd;
525 	}
526         delete grouplist;
527     }
528 
529     this->clearAssignment();
530     this->assignment = newAss;
531     this->dirty = FALSE;
532 }
533 
534 
detachGroup(const char * host,const char * group)535 void   ProcessGroupManager::detachGroup(const char *host, const char *group)
536 {
537     DXPacketIF *p = theDXApplication->getPacketIF();
538     if (NOT p)
539         return;
540 
541     char* cmd = new char[STRLEN("Executive( group detach );") + 10
542                          + STRLEN(host) + STRLEN(group)];
543 
544     sprintf(cmd, "Executive(\"group detach\",{\"%s\"});\n", group);
545 
546     p->send(PacketIF::FOREGROUND, cmd);
547     p->sendImmediate("sync");
548 
549     delete cmd;
550 
551 }
552 
attachGroup(const char * host,const char * group)553 void ProcessGroupManager::attachGroup(const char *host, const char *group)
554 {
555     DXPacketIF *p = theDXApplication->getPacketIF();
556     if (NOT p)
557         return;
558 
559     this->clearGroupHostDirty(group);
560 
561     const char* args = this->getArgument(host);
562     char* cmd = new char[STRLEN("Executive( group attach );") + 10
563                          + STRLEN(host) + STRLEN(args) + STRLEN(group)];
564 
565     if(args)
566     	sprintf(cmd, "Executive(\"group attach\", {\"%s: %s %s\"});\n",
567 			    	group,host,args);
568     else
569     	sprintf(cmd, "Executive(\"group attach\", {\"%s: %s\"});\n",
570 			    	group,host);
571 
572     p->send(PacketIF::FOREGROUND, cmd);
573     p->sendImmediate("sync");
574 
575     delete cmd;
576 }
577 
addGroupAssignment(const char * host,const char * group)578 boolean ProcessGroupManager::addGroupAssignment(const char* host,
579 						const char *group)
580 {
581     if(NOT this->assignment)
582     {
583 	this->assignment = this->createAssignment();
584 	this->sendAssignment(ATTACH);
585 	return TRUE;
586     }
587 
588     List *list = (List*)this->assignment->findDefinition(host);
589     if(NOT list)
590     {
591 	list = new List();
592 	if(NOT this->assignment->addDefinition(host, (void*)list))
593 	    return FALSE;
594     }
595 
596     list->appendElement((void*)DuplicateString(group));
597     this->attachGroup(host, group);
598 
599     return TRUE;
600 }
601 
removeGroupAssignment(const char * group)602 boolean ProcessGroupManager::removeGroupAssignment(const char *group)
603 {
604     if(NOT this->assignment)
605 	return FALSE;
606 
607     List *list;
608     ListIterator li;
609     int i, size = this->assignment->getSize();
610     boolean found;
611     char *name;
612 
613     for(i=1; i<=size; i++)
614     {
615     	list = (List*)this->assignment->getDefinition(i);
616 	found = FALSE;
617 	li.setList(*list);
618 	while( (name = (char*)li.getNext()) )
619 	    if(EqualString(name, group))
620 	    {
621 		found = TRUE;
622 		break;
623 	    }
624 
625     	if(found)
626 	{
627 	    list->removeElement((void*)name);
628 	    if(NOT this->isDirty())
629 	    	this->detachGroup(this->assignment->getStringKey(i), group);
630 
631     	    if(list->getSize() == 0)
632 		this->assignment->removeDefinition((void*)list);
633 
634     	    if(this->assignment->getSize() == 0)
635 		this->clearAssignment();
636 
637 	    return TRUE;
638         }
639     }
640 
641     return FALSE;
642 }
643 
printComment(FILE * f)644 boolean ProcessGroupManager::printComment(FILE *f)
645 {
646 
647     int	  i;
648     List  *list;
649     ListIterator li;
650     const char  *host, *args, *group;
651 
652     if(NOT this->assignment)
653 	return TRUE;
654 
655     if (fprintf(f, "//\n") <= 0)
656 	return FALSE;
657 
658     for(i=1; i <= this->assignment->getSize(); i++)
659     {
660 	host = this->assignment->getStringKey(i);
661 	args = this->getArgument(host);
662 	list = (List*)this->assignment->getDefinition(i);
663 
664 	if(args)
665 	{
666     	    if (fprintf(f, "// pgroup assignment: \"%s(%s): ", host,args) <= 0)
667 	    	return FALSE;
668 	}
669 	else
670 	{
671     	    if (fprintf(f, "// pgroup assignment: \"%s: ", host) <= 0)
672 	    	return FALSE;
673 	}
674 
675     	li.setList(*list);
676 
677 	group = (char*)li.getNext();
678 	if (fprintf(f, "%s", group) <= 0)
679             return FALSE;
680 
681     	while( (group = (char*)li.getNext()) )
682 	    if (fprintf(f, ", %s", group) <= 0)
683 		return FALSE;
684 
685 	if (fprintf(f, "\"\n") <= 0)
686 	    return FALSE;
687     }
688 
689     return TRUE;
690 }
691 
printAssignment(FILE * f)692 boolean ProcessGroupManager::printAssignment(FILE *f)
693 {
694     if (NOT this->assignment)
695 	return TRUE;
696 
697     List *list;
698     ListIterator li;
699     int i;
700     boolean first;
701     char *func, *host, *grouplist,*group, *cmd;
702 
703 	func = "group attach";
704 
705 	if(fprintf(f, "\n") <= 0)
706 	    return FALSE;
707 
708         for(i = 1; i <= this->assignment->getSize(); i++)
709         {
710             host = (char*)this->assignment->getStringKey(i);
711 	    const char *args = this->getArgument(host);
712             list = (List*)this->assignment->getDefinition(i);
713 
714 	    /* figure out how much, and allocate space for all group names */
715 	    int grouplistSize = 0;
716 	    li.setList(*list);
717 	    while( (group = (char*)li.getNext()) )
718 		grouplistSize += STRLEN(group);
719 	    grouplist = new char[grouplistSize + 20 * list->getSize()];
720 	    grouplist[0] = '\0';
721 
722 
723             first = TRUE;
724             li.setList(*list);
725             while( (group = (char*)li.getNext()) )
726 	    {
727                 if(first)
728                 {
729                     strcpy(grouplist, group);
730                     first = FALSE;
731                 }
732                 else
733                 {
734                     strcat(grouplist, ",");
735                     strcat(grouplist, group);
736                 }
737 	   }
738            cmd = new char[STRLEN("exective( ), ")
739                           + STRLEN(func)
740                           + STRLEN(host)
741                           + STRLEN(args)
742                           + STRLEN(grouplist) + 20];
743 
744 	   if(args)
745                SPRINTF(cmd, "Executive(\"%s\",{\"%s: %s %s\"});\n",
746 				   	func,grouplist,host,args);
747 	   else
748                SPRINTF(cmd, "Executive(\"%s\",{\"%s: %s\"});\n",
749 				   	func,grouplist,host);
750 
751 	   if(fprintf(f, "%s", cmd) <= 0)
752 		return FALSE;
753 
754 	   if(fprintf(f, "$sync\n") <= 0)
755 	        return FALSE;
756 
757            delete grouplist;
758            delete cmd;
759         }
760 
761 
762     return TRUE;
763 }
764 
765 //
766 // Parse the group information from the cfg file.
767 //
parseComment(const char * comment,const char * filename,int lineno,Network * net)768 boolean ProcessGroupManager::parseComment(const char *comment,
769                                 const char *filename, int lineno,Network *net)
770 {
771 
772     char *p, *c, *host, *args;
773 
774     if (strncmp(comment," pgroup assignment",STRLEN(" pgroup assignment")))
775         return FALSE;
776 
777     char *line = DuplicateString(comment);
778 
779     p = (char *) strchr(comment,'"');
780     if (!p)
781 	goto error;
782 
783     // Parse the host name.
784     host = p + 1;
785     p = strchr(host,'"');
786     if (!p)
787 	goto error;
788 
789     p = strchr(host,':');
790     if (!p)
791 	goto error;
792 
793     *p = '\0';
794 
795     // Parse the options.
796     args = strchr(host,'(');
797     if (args)
798     {
799 	*args++ = '\0';
800 	c = strchr(args,')');
801         if (!c)
802 	   goto error;
803 	*c = '\0';
804     }
805 
806     p++;
807     SkipWhiteSpace(p);
808 
809     while(*p)
810     {
811 	c = strchr(p, ',');
812 	if(!c)
813 	    c = strchr(p, '"');
814 
815 	*c = '\0';
816 
817 	this->registerGroup(p, net);
818 	this->assignHost(p, host);
819 
820 	*c = ',';
821 	p = c + 1;
822 
823 	SkipWhiteSpace(p);
824     }
825 
826     if(args)
827 	this->assignArgument(host, args);
828 
829     this->updateHosts();
830     this->clearAssignment();
831     this->assignment = this->createAssignment();
832 
833     this->dirty = TRUE;
834 
835     delete line;
836     return TRUE;
837 
838 error:
839 
840     ErrorMessage("Bad process group aasignment(%s, line %d).",filename,lineno);
841     delete line;
842     return FALSE;
843 }
844 
removeGroup(const char * name,Network * net)845 boolean ProcessGroupManager::removeGroup(const char *name, Network *net)
846 {
847     boolean ret = this->GroupManager::removeGroup (name, net);
848     this->removeGroupAssignment(name);
849 
850     return ret;
851 }
852 
853