Montag, 29 September 2008

Pragmatische Visualisierung einer Architektur

Die einfachste und schnellste Methode ein bestehendes System zu visualisieren liegt in der Auswertung der Membervariablen jeglicher Klasse und die Erzeugung eines gerichteten Graphen. Natürlich werden hier Objekte die per Übergabe in Methoden verwendet werden nicht betrachtet sowie auch Singleton Klassen auf die man über die static Methoden zugreift. Aber wie gesagt, die Vorgehensweise verschafft einen ersten Einblick.

Das Resultat zum nachfolgenden Beispiel:

Dabei wird mit Hilfe von Reflection und Graphviz einem Tool zur grafischen Darstellung von Hierarchien und Netzwerken ein Architekturbild im gewünschten Format erzeugen. Graphviz eignet sich vor allem deswegen, weil ab einer gewissen größe eines System, das manuelle Layout nicht mehr einfach ist. Die Layoutalgorithmen von Graphviz können auch mehr als 100 oder 1000 Knoten noch immer transparent darstellen.

Folgende Vorgehensweise wird hier durchgeführt:

  1. Auslesen aller Klassen eines definierten Source-Verzeichnisses.
  2. Über eine Schleife werden alle MemberVariablen über die Methode
    classloader.loadClass(name).getDeclaredFields()
    ausgelesen.
  3. Jeder Schleifendurchlauf schreibt die Memeberbeziehung zu einer anderen Klasse in ein DOT-File (Graphvizformat)<./li>

Beispiel:
Drei Klassen, wobei jede die anderen kennt.
test2.java
   1:public class Class1 {
   2:    private Class2 class2;
   3:    private Class3 class3;
   4:}
   5:
   6:public class Class2 {
   7:    private Class1 class1;
   8:    private Class3 class3;
   9:}
  10:
  11:public class Class3 {
  12:    private Class2 class2;
  13:    private Class1 class1;
  14:}
Klasse, welche die Klassen ausliest und per Reflection die Beziehung zwischen diesen identifiziert sowie das DOT-File erezugt.
test2.java
   1:package org.developersblog.PragmaticVisualizeArchiteture;
   2:
   3:import java.io.File;
   4:import java.io.FileWriter;
   5:import java.io.IOException;
   6:import java.lang.reflect.Field;
   7:import java.util.ArrayList;
   8:import java.util.List;
   9:
  10:public class MemberExtractionAndDotGeneration {
  11:
  12:    public static void getClassNames(String prefix, 
  13:            List<String> classnames,
  14:            String dir) {
  15:        File dirFile = new File(dir);
  16:        for (File file : dirFile.listFiles()) {
  17:            if (file.isDirectory()) {
  18:                if (prefix.length() > 0) {
  19:                    getClassNames(prefix + "." + 
  20:                            file.getName(), 
  21:                            classnames,
  22:                            file.getAbsolutePath());
  23:                } else {
  24:                    getClassNames(file.getName(), classnames, 
  25:                            file.getAbsolutePath());
  26:                }
  27:            } else {
  28:                if (file.getName().endsWith(".java")) {
  29:                    if (prefix.length() > 0) {
  30:                        String name = prefix + "." + file.getName().
  31:                                replaceAll(".java", "");
  32:                        classnames.add(name);
  33:                    } else {
  34:                        String name = 
  35:                                file.getName().replaceAll(".java", "");
  36:                        classnames.add(name);
  37:                    }
  38:                }
  39:            }
  40:        }
  41:    }
  42:
  43:    /**
  44:     * @param args
  45:     * @throws ClassNotFoundException
  46:     * @throws SecurityException
  47:     * @throws IOException
  48:     */
  49:    public static void main(String[] args) throws SecurityException,
  50:            ClassNotFoundException, IOException {
  51:        FileWriter writer = new FileWriter(new File(
  52:                "/home/rafsob/Desktop/graph.dot"));
  53:        writer.write("digraph G {\r\nedge [len=2];\r\n");
  54:        ClassLoader cl = MemberExtractionAndDotGeneration.
  55:                class.getClassLoader();
  56:        List<String> classnames = new ArrayList<String>();
  57:        //Klassen aus dem src Verzeichnis holen
  58:        getClassNames("", classnames,
  59:          "/home/rafsob/Desktop/workspace/" +
  60:          "PragmaticVisualizeArchiteture/src/main/java");
  61:        //Klassenreferenzen identifizieren
  62:        for (String name : classnames) {
  63:            System.out.println("check class with name: " + name);
  64:            for (Field field : cl.loadClass(name).getDeclaredFields()) {
  65:                if (classnames.contains(field.getType().getCanonicalName()) && 
  66:                    !name.equals(field.getType().getCanonicalName())) {
  67:                    
  68:                    int lastFirst = name.lastIndexOf('.');
  69:                    int lastSecond = field.getType().
  70:                            getCanonicalName().lastIndexOf('.');
  71:                    //Knotenbeziehung in DOT defnieren
  72:                    writer.write(" \"" + name.substring(lastFirst + 1) + "\" -> \"" + 
  73:                            field.getType().getCanonicalName().
  74:                            substring(lastSecond + 1) + "\";\r\n");
  75:                }
  76:            }
  77:        }
  78:        writer.write("}");
  79:        writer.close();
  80:        //Neato für die Darstellung von Graphen starten
  81:        Process p = Runtime.getRuntime().exec(
  82:                "/usr/bin/neato " +
  83:                "-Tpng /home/rafsob/Desktop/graph.dot " +
  84:                "-o /home/rafsob/Desktop/graph.png");
  85:        System.out.println("end");
  86:    }
  87:}
  88:
  89:
Viele Grüße Rafael Sobek

Technorati Tags:

Posted by rafael.sobek at 2:59 PM in Architektur
« September »
MoDiMiDoFrSaSo
1234567
891011121314
15161718192021
22232425262728
2930