From 70172e299343debdec19ef8bec204f25c6552338 Mon Sep 17 00:00:00 2001 From: Rene Krenn Date: Fri, 27 Aug 2021 20:16:32 +0200 Subject: [PATCH] TT#136902 render UML class diagrams Change-Id: I3fe040e3a277bb4c2c937450b2b6540fd6f324dc (cherry picked from commit 854ed66481cf7443e46380dedf14864b52dd6ff0) --- .../mr341/provisioning/voip_subscribers.pm | 2 +- render_class_diagrams.pl | 388 ++++++++++++++++++ 2 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 render_class_diagrams.pl diff --git a/lib/NGCP/BulkProcessor/Dao/mr341/provisioning/voip_subscribers.pm b/lib/NGCP/BulkProcessor/Dao/mr341/provisioning/voip_subscribers.pm index 524b0ce9..b6a59509 100644 --- a/lib/NGCP/BulkProcessor/Dao/mr341/provisioning/voip_subscribers.pm +++ b/lib/NGCP/BulkProcessor/Dao/mr341/provisioning/voip_subscribers.pm @@ -23,7 +23,7 @@ use NGCP::BulkProcessor::SqlRecord qw(); use NGCP::BulkProcessor::Dao::mr341::provisioning::voip_dbaliases qw(); use NGCP::BulkProcessor::Dao::mr341::provisioning::voip_usr_preferences qw(); use NGCP::BulkProcessor::Dao::mr341::kamailio::voicemail_users qw(); -use NGCP::BulkProcessor::Dao::mr341::kamailio::locations qw(); +use NGCP::BulkProcessor::Dao::mr341::kamailio::location qw(); use NGCP::BulkProcessor::Dao::mr341::provisioning::voip_trusted_sources qw(); use NGCP::BulkProcessor::Dao::mr341::provisioning::voip_cf_destination_sets qw(); diff --git a/render_class_diagrams.pl b/render_class_diagrams.pl new file mode 100644 index 00000000..2aaafccd --- /dev/null +++ b/render_class_diagrams.pl @@ -0,0 +1,388 @@ +use strict; + +use File::Basename; +use Cwd; +use lib Cwd::abs_path(File::Basename::dirname(__FILE__)); + +use NGCP::BulkProcessor::Globals qw($system_version + $system_abbreviation + $system_instance_label + $application_path +); + +our $umldiagrampath = Cwd::abs_path(File::Basename::dirname(__FILE__)) . '/uml/'; + +our $uml_diagram_format = 'dot'; #'png' + +use NGCP::BulkProcessor::Utils qw( + getscriptpath + cleanupdir + makepath + changemod + getscriptpath +); + +use NGCP::BulkProcessor::Array qw(contains); + +use NGCP::BulkProcessor::Logging qw( + getlogger + scriptinfo +); +use NGCP::BulkProcessor::LogError qw( + fileerror + filewarn + done +); + +use File::Find; +use File::Basename; +use UML::Class::Simple; + +my $graphviz_dot_path; +if ($^O eq 'MSWin32') { + # IPC run3 used in UML::Class::Simple obviously ignores windows (vista 32) + # PATH variable. so we specify the path to graphviz dot.exe manually: + #$graphviz_dot_path = 'C:\Program Files\Graphviz2.26.3\bin\dot.exe'; + $graphviz_dot_path = 'C:\Program Files (x86)\Graphviz2.26.3\bin\dot.exe'; +} else { + # unix probably ok - leave UML::Class::Simple alone: + $graphviz_dot_path = undef; +} + +my $logger = getlogger(getscriptpath()); + +my @dirs_to_skip = (); +push @dirs_to_skip,$application_path . "Dao/mr553/"; +push @dirs_to_skip,$application_path . "Dao/mr457/"; +push @dirs_to_skip,$application_path . "Dao/mr441/"; +push @dirs_to_skip,$application_path . "Dao/mr341/"; +push @dirs_to_skip,$application_path . "Dao/mr103/"; +#push @dirs_to_skip,$application_path . "Dao/mr102/"; +push @dirs_to_skip,$application_path . "Dao/mr38/"; +push @dirs_to_skip,$application_path . "Dao/Trunk/accounting"; +push @dirs_to_skip,$application_path . "Dao/Trunk/billing"; +push @dirs_to_skip,$application_path . "Dao/Trunk/kamailio"; + +push @dirs_to_skip,$application_path . "Redis/mr65/"; +push @dirs_to_skip,$application_path . "RestRequests/"; +push @dirs_to_skip,$application_path . "Service/"; +push @dirs_to_skip,$application_path . "RestConnectors/"; + +push @dirs_to_skip,$application_path . "Projects/t/"; +push @dirs_to_skip,$application_path . "Projects/ETL/"; +push @dirs_to_skip,$application_path . "Projects/Export/"; +push @dirs_to_skip,$application_path . "Projects/Disaster/"; +push @dirs_to_skip,$application_path . "Projects/Migration/"; +push @dirs_to_skip,$application_path . "Projects/Massive/Generator/"; +push @dirs_to_skip,$application_path . "Projects/Massive/RegistrationMonitoring/"; + +#push @dirs_to_skip,$application_path . "FileProcessors/"; + +my $public_only = 1; +my $inherited_methods = 0; + +#my @perlfileextensions = ('.pm'); #('.pl','.pm'); +my @perlfileextensions = ('.pm'); +my $rperlextensions = join('|',map { local $_ = $_ ; $_ = quotemeta($_); $_; } @perlfileextensions); + +my @parsedfiles = (); + +my $mode = $ARGV[0]; + +eval { + + my $painter; + my $outputfilepath; + + if ('cleanup' eq $mode) { + cleanupdir($umldiagrampath,0,\&scriptinfo,\&filewarn,$logger); + } elsif ('all' eq $mode) { + find({ wanted => \&dir_names, follow => 1 }, $application_path); + + $outputfilepath = $umldiagrampath . '_' . $system_abbreviation . '_' . $system_instance_label . '.' . $uml_diagram_format; + + $painter = getpainter(\@parsedfiles); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('dao_ngcp' eq $mode) { + $outputfilepath = $umldiagrampath . '_dao_ngcp.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'SqlRecord.pm', + $application_path . 'Dao/Trunk/provisioning/voip_subscribers.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('dao_openser' eq $mode) { + $outputfilepath = $umldiagrampath . '_dao_openser.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'SqlRecord.pm', + $application_path . 'Dao/mr102/openser/location.pm', + $application_path . 'Dao/mr102/openser/voicemail_users.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('dao_regmon' eq $mode) { + $outputfilepath = $umldiagrampath . '_dao_regmon.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'SqlRecord.pm', + $application_path . 'Projects/Massive/VodafoneRO/RegistrationMonitoring/Dao/Proc4SwDynamic.pm', + $application_path . 'Projects/Massive/VodafoneRO/RegistrationMonitoring/Dao/Proc4SwStatic.pm', + $application_path . 'Projects/Massive/VodafoneRO/RegistrationMonitoring/Dao/SwStatus.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('dao_cmtsmon' eq $mode) { + $outputfilepath = $umldiagrampath . '_dao_cmtsmon.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'SqlRecord.pm', + $application_path . 'Projects/Massive/VodafoneRO/CmtsMonitoring/Dao/SwInputDynamic.pm', + $application_path . 'Projects/Massive/VodafoneRO/CmtsMonitoring/Dao/SwOutput.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('sql_connectors' eq $mode) { + $outputfilepath = $umldiagrampath . '_sql_connectors.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'SqlConnector.pm', + $application_path . 'SqlProcessor.pm', + $application_path . 'SqlRecord.pm', + $application_path . 'SqlConnectors/MySQLDB.pm', + $application_path . 'SqlConnectors/OracleDB.pm', + $application_path . 'SqlConnectors/SQLiteDB.pm', + $application_path . 'SqlConnectors/CSVDB.pm', + $application_path . 'SqlConnectors/SQLServerDB.pm', + $application_path . 'SqlConnectors/PostgreSQLDB.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('no_sql_connectors' eq $mode) { + $outputfilepath = $umldiagrampath . '_no_sql_connectors.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'NoSqlConnector.pm', + $application_path . 'NoSqlConnectors/Redis.pm', + $application_path . 'NoSqlConnectors/RedisEntry.pm', + $application_path . 'NoSqlConnectors/RedisProcessor.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('redis' eq $mode) { + $outputfilepath = $umldiagrampath . '_redis.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'NoSqlConnectors/RedisEntry.pm', + $application_path . 'Redis/mr755/location/usrdom.pm', + $application_path . 'Redis/mr755/location/entry.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('framework1' eq $mode) { + $outputfilepath = $umldiagrampath . '_framework1.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'Array.pm', + $application_path . 'Calendar.pm', + $application_path . 'ConnectorPool.pm', + $application_path . 'DSPath.pm', + $application_path . 'DSSorter.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('framework3' eq $mode) { + $outputfilepath = $umldiagrampath . '_framework3.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'FileProcessor.pm', + $application_path . 'Globals.pm', + $application_path . 'LoadConfig.pm', + $application_path . 'LogError.pm', + $application_path . 'Logging.pm', + $application_path . 'Mail.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } elsif ('framework2' eq $mode) { + $outputfilepath = $umldiagrampath . '_framework2.' . $uml_diagram_format; + $painter = getpainter([ + $application_path . 'RestConnector.pm', + $application_path . 'RestItem.pm', + $application_path . 'RestProcessor.pm', + $application_path . 'Serialization.pm', + $application_path . 'Table.pm', + $application_path . 'Utils.pm', + ]); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo($outputfilepath . ' created',$logger); + } else { + print STDERR "Could not create $outputfilepath.\n"; + } + } +}; +if ($@) { + exit(1); +} else { + done(undef,undef,$logger); + exit(0); +} + +sub dir_names { + + my $path = $File::Find::dir; + $path .= '/' . $_ if ($_ ne '.' and $_ ne '..'); + if (-d $path) { + my $dir = $path . '/'; + unless (scalar grep { index($dir, $_, 0) == 0; } @dirs_to_skip) { + #print 'creating perldoc html files for source files in ' . $path . "\n"; + push @parsedfiles,createumldiagramsofdir($dir,$umldiagrampath . substr($dir,length($application_path))); + #push @dirs_to_skip,$dir; + } + } +} + +sub createumldiagramsofdir { + + my ($inputdir,$outputdir) = @_; + makepath($outputdir); + + local *DOCDIR; + if (not opendir(DOCDIR, $inputdir)) { + fileerror('cannot opendir ' . $inputdir . ': ' . $!,$logger); + return; + } + my @files = grep { /$rperlextensions$/ && -f $inputdir . $_} readdir(DOCDIR); + closedir DOCDIR; + + my @inputfilepaths = (); + + foreach my $file (@files) { + my $inputfilepath = $inputdir . $file; + my ($inputfilename,$inputfiledir,$inputfilesuffix) = fileparse($inputfilepath, $rperlextensions); + my $outputfilepath = $outputdir . $inputfilename . '.' . $uml_diagram_format; #'.png'; + #unlink $outputfilepath; + + my $painter = getpainter($inputfilepath); + + # we can explicitly specify the image size + #$painter->size(5, 3.6); # in inches + + # ...and change the default title background color: + #$painter->node_color('#ffffff'); # defaults to '#f1e1f4' + + # only show public methods and properties + #$painter->public_only(1); + + # hide all methods from parent classes + #$painter->inherited_methods(0); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + changemod($outputfilepath); + push @inputfilepaths,$inputfilepath; + scriptinfo('uml diagram ' . $outputfilepath . ' created for source file ' . $inputfilepath,$logger); + } else { + # write message to STDERR make it look the same as perldoc + print STDERR 'Could not create uml diagram for "' . $inputfilepath . "\".\n"; + } + } + + if (scalar @inputfilepaths > 0) { + + my @dirparts = File::Spec->splitdir($inputdir); + my $outputfilepath = $outputdir . $dirparts[$#dirparts - 1] . '.' . $uml_diagram_format; #'.png'; + + my $painter = getpainter(\@inputfilepaths); + + # we can explicitly specify the image size + #$painter->size(5, 3.6); # in inches + + # ...and change the default title background color: + #$painter->node_color('#ffffff'); # defaults to '#f1e1f4' + + # only show public methods and properties + #$painter->public_only(1); + + # hide all methods from parent classes + #$painter->inherited_methods(0); + + if (outputpainter($painter,$outputfilepath) and -e $outputfilepath) { + scriptinfo('uml diagram ' . $outputfilepath . ' created for source dir ' . $inputdir,$logger); + } else { + # write message to STDERR make it look the same as perldoc + print STDERR 'Could not create uml diagram for dir "' . $inputdir . "\".\n"; + } + } + + return @inputfilepaths; + +} + +sub getpainter { + + my $inputfilepaths = shift; + + my @classes = classes_from_files($inputfilepaths); + my $painter = UML::Class::Simple->new(\@classes); + if ($graphviz_dot_path) { + $painter->{dot_prog} = $graphviz_dot_path; + } + + $painter->public_only($public_only); + $painter->inherited_methods($inherited_methods); + #$painter->size(8.3, 11.7); + + return $painter; + +} + +sub outputpainter { + + my ($painter,$outputfilepath) = @_; + + if (scalar @{$painter->as_dom()->{classes}} > 0) { + if ($uml_diagram_format eq 'png') { + $painter->as_png($outputfilepath); + } elsif ($uml_diagram_format eq 'dot') { + $painter->as_dot($outputfilepath); + } + return 1; + } else { + return 0; + } + +}