new tab line, renaming players works now

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.LinearGradientPaint;

import javax.swing.JPanel;
import javax.swing.JTabbedPane;

import model.SystemValues.Games;
import model.SystemValues.Players;
import view.GUI;
import view.UIUpdater;
import de.erichseifert.gral.data.DataTable;
import de.erichseifert.gral.plots.BarPlot;
import de.erichseifert.gral.plots.BarPlot.BarRenderer;
import de.erichseifert.gral.plots.PiePlot;
import de.erichseifert.gral.plots.PiePlot.PieSliceRenderer;
import de.erichseifert.gral.plots.points.PointRenderer;
import de.erichseifert.gral.ui.InteractivePanel;
import de.erichseifert.gral.util.GraphicsUtils;
import de.erichseifert.gral.util.Insets2D;
import de.erichseifert.gral.util.Location;

public privileged aspect StatPlayerWiseGraph {
    /**
     * Statistics has to be the last feature executed, such that the subfeatures
     * have the correct gui object before statistics can create the tabbed pane
     */
    declare precedence : Statistics, StatPlayerWiseGraph, StatPlayerWiseTxt, StatOverallGraph, StatOverallTxt;

    private static GUI gui;

    private static final JTabbedPane playersTabs = new JTabbedPane();
    private static final Color COLOR1 = Color.GREEN;

    private static DataTable playedTypes[] = new DataTable[4];
    private static DataTable wonGames[] = new DataTable[4];

    after() returning(GUI gui): call(GUI.new(*)) {
        StatPlayerWiseGraph.gui = gui;
    }

    @SuppressWarnings("unchecked")
    after(JTabbedPane tabbedPane):
                        execution(public static void StatisticsHelper.StatisticsPaneCreated(JTabbedPane))
                        && args(tabbedPane) {

        for (int i = 0; i < Players.values().length; i++) {
            playedTypes[i] = new DataTable(Integer.class, String.class);
            wonGames[i] = new DataTable(Integer.class, Double.class,String.class);
        }

        updateData();
;
        for (Players player : Players.values()) {
            playersTabs.addTab(player.toString(), createPlayersPanel(player));
        }
        tabbedPane.addTab("Einzelstatistiken", playersTabs);
    }

    private JPanel createPlayersPanel(Players player) {
        JPanel containerPanel = new JPanel();
        containerPanel.setLayout(new GridLayout(2, 2));

        containerPanel.add(new InteractivePanel(createWonGamesBarPlot(player)));
        containerPanel.add(new InteractivePanel(createPlayedTypesPlot(player)));
        return containerPanel;
    }

    after() : execution(* UIUpdater.run()) {
        updateData();
        for (Players player : Players.values()) {
            playersTabs.setTitleAt(player.ordinal(), player.toString());
        }
    }

    private static void updateData() {
        for (Players player : Players.values()) {
            PlayerWiseStatistics data = gui.model.getGameData()
                    .getPlayerWiseStatistics(player);

            int i = player.ordinal();

            while (playedTypes[i].getRowCount() > 0) {
                playedTypes[i].removeLast();
            }
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.RUFSPIEL.ordinal()],
                    "Rufspiele");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.SOLO.ordinal()], "Soli");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.TOUT.ordinal()],
                    "Soli Tout");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.SIE.ordinal()],
                    "Soli Sie");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.WEITER.ordinal()],
                    "Weiter");

            // percentage of won games by gametype
            int soli_complete_amount = data.getGamesPlayedPerType()[Games.SOLO
                    .ordinal()]
                    + data.getGamesPlayedPerType()[Games.SIE.ordinal()]
                    + data.getGamesPlayedPerType()[Games.TOUT.ordinal()];
            int soli_complete_amount_won = data.getGamesWonPerType()[Games.SOLO
                    .ordinal()]
                    + data.getGamesWonPerType()[Games.SIE.ordinal()]
                    + data.getGamesWonPerType()[Games.TOUT.ordinal()];
            double soli_gesamt_won_perc = soli_complete_amount > 0 ? (double) soli_complete_amount_won
                    / soli_complete_amount
                    : 0.0;

            while (wonGames[i].getRowCount() > 0) {
                wonGames[i].removeLast();
            }
            wonGames[i].add(1, data.getGamesWonPerc(), "Gesamt");
            wonGames[i].add(2,
                    data.getGamesWonPerTypePerc()[Games.RUFSPIEL.ordinal()],
                    "Rufspiele");
            wonGames[i].add(3, soli_gesamt_won_perc, "Soli gesamt");
            wonGames[i].add(4,
                    data.getGamesWonPerTypePerc()[Games.SOLO.ordinal()],
                    "Soli normal");
            wonGames[i].add(5,
                    data.getGamesWonPerTypePerc()[Games.TOUT.ordinal()],
                    "Soli Tout");
            wonGames[i].add(6,
                    data.getGamesWonPerTypePerc()[Games.SIE.ordinal()],
                    "Soli Sie");
        }
    }

    private static PiePlot createPlayedTypesPlot(Players player) {
        int playerIndex = player.ordinal();

        PiePlot plot = new PiePlot(playedTypes[playerIndex]);

        PointRenderer pointRenderer = plot
                .getPointRenderer(playedTypes[playerIndex]);
        pointRenderer.setValueVisible(true);
        pointRenderer.setValueColumn(1);

        // Format plot
        plot.getTitle().setText("Anzahl gespielter Spieltypen");
        // Change plot size
        plot.setRadius(0.9);
        // Display a legend
        plot.setLegendVisible(true);
        // Add some margin to the plot area
        plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0));

        PieSliceRenderer pieSliceRenderer = (PieSliceRenderer) plot
                .getPointRenderer(playedTypes[playerIndex]);

        // Change relative size of inner region
        pieSliceRenderer.setInnerRadius(0.4);
        // Change the width of gaps between segments
        pieSliceRenderer.setGap(0.2);
        // Show labels
        pieSliceRenderer.setValueVisible(true);
        pieSliceRenderer.setValueColor(Color.WHITE);
        pieSliceRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD));

        return plot;
    }

    public BarPlot createWonGamesBarPlot(Players player) {
        int playerIndex = player.ordinal();

        // Create new bar plot
        BarPlot plot = new BarPlot(wonGames);

        // Format plot
        plot.getTitle().setText("Gewonnene Spiele pro Spieltyp (in %)");
        plot.setInsets(new Insets2D.Double(40.0, 40.0, 40.0, 40.0));
        plot.setBarWidth(0.075);

        // Format bars
        PointRenderer pointRenderer = plot
                .getPointRenderer(wonGames[playerIndex]);
        BarRenderer barRenderer = (BarRenderer) pointRenderer;

        barRenderer.setColor(new LinearGradientPaint(0f, 0f, 0f, 1f,
                new float[] { 0.0f, 1.0f }, new Color[] { COLOR1,
                        GraphicsUtils.deriveBrighter(COLOR1) }));
        barRenderer.setBorderStroke(new BasicStroke(3f));
        barRenderer.setBorderColor(new LinearGradientPaint(0f, 0f, 0f, 1f,
                new float[] { 0.0f, 1.0f }, new Color[] {
                        GraphicsUtils.deriveBrighter(COLOR1), COLOR1 }));

        pointRenderer.setValueVisible(true);
        pointRenderer.setValueColumn(2);

        pointRenderer.setValueLocation(Location.CENTER);
        pointRenderer.setValueColor(GraphicsUtils.deriveDarker(COLOR1));
        pointRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD));

        return plot;
    }
}

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.LinearGradientPaint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;

import model.SystemValues.Games;
import model.SystemValues.Players;
import de.erichseifert.gral.data.DataTable;
import de.erichseifert.gral.plots.BarPlot;
import de.erichseifert.gral.plots.PiePlot;
import de.erichseifert.gral.ui.InteractivePanel;
import de.erichseifert.gral.plots.BarPlot.BarRenderer;
import de.erichseifert.gral.plots.PiePlot.PieSliceRenderer;
import de.erichseifert.gral.plots.points.PointRenderer;
import de.erichseifert.gral.util.GraphicsUtils;
import de.erichseifert.gral.util.Insets2D;
import de.erichseifert.gral.util.Location;
import view.GUI;
import view.UIUpdater;
import model.db.GameData;

public privileged aspect StatPlayerWiseGraph {
    /**
     * Statistics has to be the last feature executed, such that the subfeatures
     * have the correct gui object before statistics can create the tabbed pane
     */
    declare precedence : Statistics, StatPlayerWiseGraph, StatPlayerWiseTxt, StatOverallGraph, StatOverallTxt;

    private static GUI gui;
    private static JPanel containerPanel = new JPanel();
    private static JPanel buttonPanel = new JPanel();
    private static JPanel[] graphPanels = new JPanel[4];

    private static final Color COLOR1 = Color.GREEN;

    private static DataTable playedTypes[] = new DataTable[4];
    private static DataTable wonGames[] = new DataTable[4];

    after() returning(GUI gui): call(GUI.new(*)) {
        StatPlayerWiseGraph.gui = gui;
    }

    after(JTabbedPane tabbedPane):
                        execution(public static void StatisticsHelper.StatisticsPaneCreated(JTabbedPane))
                        && args(tabbedPane) {
        for (int i = 0; i < graphPanels.length; i++) {
            graphPanels[i] = new JPanel();
            playedTypes[i] = new DataTable(Integer.class, String.class);
            wonGames[i] = new DataTable(Integer.class, Double.class,
                    String.class);

        }

        updateData();

        JRadioButton player1CheckBox = new JRadioButton("Spieler 1");
        JRadioButton player2CheckBox = new JRadioButton("Spieler 2");
        JRadioButton player3CheckBox = new JRadioButton("Spieler 3");
        JRadioButton player4CheckBox = new JRadioButton("Spieler 4");

        player1CheckBox.setSelected(true);
        ButtonGroup buttonGroup = new ButtonGroup();
        buttonGroup.add(player1CheckBox);
        buttonGroup.add(player2CheckBox);
        buttonGroup.add(player3CheckBox);
        buttonGroup.add(player4CheckBox);

        player1CheckBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                containerPanel.remove(1);
                containerPanel.add(graphPanels[0], BorderLayout.CENTER, 1);
                containerPanel.repaint();
            }
        });
        player2CheckBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                containerPanel.remove(1);
                containerPanel.add(graphPanels[1], BorderLayout.CENTER, 1);
                containerPanel.repaint();
            }
        });
        player3CheckBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                containerPanel.remove(1);
                containerPanel.add(graphPanels[2], BorderLayout.CENTER, 1);
                containerPanel.repaint();
            }
        });
        player4CheckBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                containerPanel.remove(1);
                containerPanel.add(graphPanels[3], BorderLayout.CENTER, 1);
                containerPanel.repaint();
            }
        });

        buttonPanel.setLayout(new FlowLayout());
        buttonPanel.add(player1CheckBox);
        buttonPanel.add(player2CheckBox);
        buttonPanel.add(player3CheckBox);
        buttonPanel.add(player4CheckBox);

        for (JPanel graphPanel : graphPanels) {
            graphPanel.setLayout(new GridLayout(2, 2));
        }

        for (Players player : Players.values()) {
            int i = player.ordinal();
            graphPanels[i].add(new InteractivePanel(
                    createWonGamesBarPlot(player)));
            graphPanels[i].add(new InteractivePanel(
                    createPlayedTypesPlot(player)));
        }

        containerPanel.setLayout(new BorderLayout());
        containerPanel.add(buttonPanel, BorderLayout.NORTH, 0);
        containerPanel.add(graphPanels[0], BorderLayout.CENTER, 1);

        tabbedPane.addTab("PlayerWiseGrafik", containerPanel);
    }

    after() : execution(* UIUpdater.run()) {
        updateData();
    }

    private static void updateData() {
        for (Players player : Players.values()) {
            PlayerWiseStatistics data = gui.model.getGameData()
                    .getPlayerWiseStatistics(player);

            int i = player.ordinal();

            while (playedTypes[i].getRowCount() > 0) {
                playedTypes[i].removeLast();
            }
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.RUFSPIEL.ordinal()],
                    "Rufspiele");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.SOLO.ordinal()], "Soli");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.TOUT.ordinal()],
                    "Soli Tout");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.SIE.ordinal()],
                    "Soli Sie");
            playedTypes[i].add(
                    data.getGamesPlayedPerType()[Games.WEITER.ordinal()],
                    "Weiter");

            // percentage of won games by gametype
            int soli_complete_amount = data.getGamesPlayedPerType()[Games.SOLO
                    .ordinal()]
                    + data.getGamesPlayedPerType()[Games.SIE.ordinal()]
                    + data.getGamesPlayedPerType()[Games.TOUT.ordinal()];
            int soli_complete_amount_won = data.getGamesWonPerType()[Games.SOLO
                    .ordinal()]
                    + data.getGamesWonPerType()[Games.SIE.ordinal()]
                    + data.getGamesWonPerType()[Games.TOUT.ordinal()];
            double soli_gesamt_won_perc = soli_complete_amount > 0 ? (double) soli_complete_amount_won
                    / soli_complete_amount
                    : 0.0;

            while (wonGames[i].getRowCount() > 0) {
                wonGames[i].removeLast();
            }
            wonGames[i].add(1, data.getGamesWonPerc(), "Gesamt");
            wonGames[i].add(2,
                    data.getGamesWonPerTypePerc()[Games.RUFSPIEL.ordinal()],
                    "Rufspiele");
            wonGames[i].add(3, soli_gesamt_won_perc, "Soli gesamt");
            wonGames[i].add(4,
                    data.getGamesWonPerTypePerc()[Games.SOLO.ordinal()],
                    "Soli normal");
            wonGames[i].add(5,
                    data.getGamesWonPerTypePerc()[Games.TOUT.ordinal()],
                    "Soli Tout");
            wonGames[i].add(6,
                    data.getGamesWonPerTypePerc()[Games.SIE.ordinal()],
                    "Soli Sie");
        }
    }

    private static PiePlot createPlayedTypesPlot(Players player) {
        int playerIndex = player.ordinal();

        PiePlot plot = new PiePlot(playedTypes[playerIndex]);

        PointRenderer pointRenderer = plot
                .getPointRenderer(playedTypes[playerIndex]);
        pointRenderer.setValueVisible(true);
        pointRenderer.setValueColumn(1);

        // Format plot
        plot.getTitle().setText("Anzahl gespielter Spieltypen");
        // Change plot size
        plot.setRadius(0.9);
        // Display a legend
        plot.setLegendVisible(true);
        // Add some margin to the plot area
        plot.setInsets(new Insets2D.Double(20.0, 40.0, 40.0, 40.0));

        PieSliceRenderer pieSliceRenderer = (PieSliceRenderer) plot
                .getPointRenderer(playedTypes[playerIndex]);

        // Change relative size of inner region
        pieSliceRenderer.setInnerRadius(0.4);
        // Change the width of gaps between segments
        pieSliceRenderer.setGap(0.2);
        // Show labels
        pieSliceRenderer.setValueVisible(true);
        pieSliceRenderer.setValueColor(Color.WHITE);
        pieSliceRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD));

        return plot;
    }

    public BarPlot createWonGamesBarPlot(Players player) {
        int playerIndex = player.ordinal();

        // Create new bar plot
        BarPlot plot = new BarPlot(wonGames);

        // Format plot
        plot.getTitle().setText("Gewonnene Spiele pro Spieltyp (in %)");
        plot.setInsets(new Insets2D.Double(40.0, 40.0, 40.0, 40.0));
        plot.setBarWidth(0.075);

        // Format bars
        PointRenderer pointRenderer = plot
                .getPointRenderer(wonGames[playerIndex]);
        BarRenderer barRenderer = (BarRenderer) pointRenderer;

        barRenderer.setColor(new LinearGradientPaint(0f, 0f, 0f, 1f,
                new float[] { 0.0f, 1.0f }, new Color[] { COLOR1,
                        GraphicsUtils.deriveBrighter(COLOR1) }));
        barRenderer.setBorderStroke(new BasicStroke(3f));
        barRenderer.setBorderColor(new LinearGradientPaint(0f, 0f, 0f, 1f,
                new float[] { 0.0f, 1.0f }, new Color[] {
                        GraphicsUtils.deriveBrighter(COLOR1), COLOR1 }));

        pointRenderer.setValueVisible(true);
        pointRenderer.setValueColumn(2);

        pointRenderer.setValueLocation(Location.CENTER);
        pointRenderer.setValueColor(GraphicsUtils.deriveDarker(COLOR1));
        pointRenderer.setValueFont(Font.decode(null).deriveFont(Font.BOLD));

        return plot;
    }
}


Create sequence diagram in the maven target folder

// TODO change the name of the file/class

// Creates sequence diagram in the target folder of maven
// TODO change it not depend on mvn target folder

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileWriter;
import java.io.File;
import java.util.Stack;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import net.sourceforge.plantuml.SourceStringReader;

class Counter{
    // TODO check equivalent of __doc__ in Java
    private String base;
    private int count;

    protected Counter(){
        // TODO check syntax to call the other Counter constructor
        this.base = "1";
        this.count = 1;
    }

    protected Counter(String base){
        this.base = base;
        this.count = 1;
    }

    Counter getNextCounter(){
        String newBase;
        if (base == ""){
            newBase = String.valueOf(count);
        }
        else{
            newBase = base + "." + String.valueOf(count);
        }
        count += 1;
        return new Counter(newBase);
    }

    // TODO just for fun want to make this protected,
    // so can i avoid inheritenc from Object?
    public String toString(){
        return base;
    }
}

public aspect SequenceDiagramGenerator{
    // TODO check if aspects can have instance variables
    // need to make these attributes non-static
    static private Stack<String> currentMethodStack= new Stack<String>();
    static private Stack<Counter> counterStack= new Stack<Counter>();
    static private String planUMLGrammar="";
    static private boolean start=true;

    pointcut traceMethods():  call(* *.*(..))   // All methods
                              && !call(* java..*(..)) // Don't want java language inbuilt objects
                              && !within(SequenceDiagramGenerator) // Not within our aspect itself, to avoid infinite reursion
                              && !within(Counter);

    pointcut traceConstructors():  execution(*.new(..)) // All constructors
                                   && !within(SequenceDiagramGenerator)
                                   && !within(Counter);

    pointcut createSeqImage():  execution(* Main.main(..));

    // TODO exploer java.io.PrintStream
    void around(String str) : call(void java.io.PrintStream.println(String))
                                && !within(SequenceDiagramGenerator)
                                && !within(Counter)
                                && args(str){
        planUMLGrammar = planUMLGrammar + "note right : " + str + "\n";
        proceed(str);
    }

    after(): createSeqImage(){
        // start = false;
        String note = "note left of aMain #FFAAAA\n<color #118888>Madhur Khandelwal\nmadhurkhandelwal.234@gmail.com \nend note\n";
        planUMLGrammar = planUMLGrammar + note;
        // System.out.println("_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+");
        // System.out.println("@startuml\n" +
        //           planUMLGrammar +
        //           "\n@enduml");
        // System.out.println("_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+");

        String jarFileLoc = Counter.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        File file = new File(jarFileLoc);
        String parentPath = file.getAbsoluteFile().getParent();
        Path path = Paths.get(parentPath, "sequenceDiagram.png");
        String outputPath = path.toString();

        createImage("@startuml\n" + planUMLGrammar + "\n@enduml", outputPath);
    }

    before(): createSeqImage(){
      start = true;
    }

    before() : traceConstructors() {
        if(start){
            Signature s =
            thisJoinPointStaticPart.getSignature();
            String methodName = s.getName();

            // use "new" for constructors.
            if (methodName.equals("") || methodName.equals("<init>")){
                methodName = "new";
            }

            // TODO show constructors in the sequence diagram
            // System.out.println(s.getDeclaringType().getSimpleName() + "."  + methodName + " {");
        }
    }

    after() : traceConstructors() {
        // if(start){
        //    System.out.println("}");
        // }
    }

    Object around() : traceMethods() {
    if(start){
        // System.out.println("##################START##################");

        MethodSignature signature = (MethodSignature)thisJoinPoint.getSignature();

        String[] parameterNames = signature.getParameterNames();
        Object[] parameterValues = thisJoinPoint.getArgs();

        //String calleClassName = signature.getDeclaringTypeName();
        String calleClassName;
        if (thisJoinPoint.getTarget() == null){
            calleClassName = signature.getDeclaringTypeName();
            // System.out.println("null aaya tha: " + thisJoinPoint.getTarget());
        }
        else{
            // TODO have diff line for objects of same type
            // System.out.println("no null: " + thisJoinPoint.getTarget());
            calleClassName = thisJoinPoint.getTarget().toString().split("@")[0];
        }
        if ("aeiou".indexOf(Character.toLowerCase((calleClassName.charAt(0)))) < 0){
            calleClassName = "a" + calleClassName;
        }
        else{
            calleClassName = "an" + calleClassName;
        }
        // System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
        // System.out.println(calleClassName);
        // System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
        String calleMethodName = signature.getName();
        String returnTypeName = signature.getReturnType().getName();

        // TODO check any functionality to explore all methods like 'dir' in python
        // maybe use reflection(why such name) API to iterate over the methods and call them
        // System.out.println("thisJoinPoint getArgs  " + thisJoinPoint.getArgs());
        // System.out.println("thisJoinPoint getKind  " + thisJoinPoint.getKind());
        // System.out.println("thisJoinPoint getSignature  " + thisJoinPoint.getSignature());
        // System.out.println("thisJoinPoint getSourceLocation  " + thisJoinPoint.getSourceLocation());
        // System.out.println("thisJoinPoint getStaticPart  " + thisJoinPoint.getStaticPart());
        // System.out.println("thisJoinPoint getTarget  " + thisJoinPoint.getTarget());
        // System.out.println("thisJoinPoint getThis  " + thisJoinPoint.getThis());
        // System.out.println("thisJoinPoint toLongString  " + thisJoinPoint.toLongString());
        // System.out.println("thisJoinPoint toShortString  " + thisJoinPoint.toShortString());
        // System.out.println("thisJoinPoint toString  " + thisJoinPoint.toString());

        // System.out.println("thisJoinPointStaticPart getKind" + thisJoinPointStaticPart.getKind());
        // System.out.println("thisJoinPointStaticPart getSignature" + thisJoinPointStaticPart.getSignature());
        // System.out.println("thisJoinPointStaticPart getSourceLocation" + thisJoinPointStaticPart.getSourceLocation());
        // System.out.println("thisJoinPointStaticPart toLongString" + thisJoinPointStaticPart.toLongString());
        // System.out.println("thisJoinPointStaticPart toShortString" + thisJoinPointStaticPart.toShortString());
        // System.out.println("thisJoinPointStaticPart toString" + thisJoinPointStaticPart.toString()  );

        // System.out.println("thisEnclosingJoinPointStaticPart getKind" + thisEnclosingJoinPointStaticPart.getKind());
        // System.out.println("thisEnclosingJoinPointStaticPart getSignature" + thisEnclosingJoinPointStaticPart.getSignature());
        // System.out.println("thisEnclosingJoinPointStaticPart getSourceLocation" + thisEnclosingJoinPointStaticPart.getSourceLocation());
        // System.out.println("thisEnclosingJoinPointStaticPart toLongString" + thisEnclosingJoinPointStaticPart.toLongString());
        // System.out.println("thisEnclosingJoinPointStaticPart toShortString" + thisEnclosingJoinPointStaticPart.toShortString());
        // System.out.println("thisEnclosingJoinPointStaticPart toString" + thisEnclosingJoinPointStaticPart.toString()  );

        // TODO
        String callerClass="";
        if (!currentMethodStack.empty()){
            callerClass = currentMethodStack.peek();
        }

        int i = 0;
        String argString="";
        for (String x: parameterNames){
            if (argString != ""){
                argString = argString + ",";
            }
            argString = argString + x + ":" + parameterValues[i].getClass().getSimpleName();
            i++;
        }

        // System.out.println("");

        // System.out.println("-> " + signature.toString());
        String currentLine1;
        String countString = updateCounter();
        if (countString != "" ){
            currentLine1 = String.format("%s -> %s: %s : %s(%s): %s\n", callerClass, calleClassName, countString,calleMethodName, argString, returnTypeName);
        }else{
            currentLine1 = String.format("%s -> %s: %s(%s): %s\n", callerClass, calleClassName, calleMethodName, argString, returnTypeName);
        }
        String currentLine2 = String.format("activate %s\n", calleClassName);
        // System.out.println("currentLine1: " + currentLine1);

        planUMLGrammar = planUMLGrammar + currentLine1 + currentLine2;
        currentMethodStack.push(calleClassName);
        for (String x: parameterNames){
            // System.out.print("----------" + x + " ");
        }
        // System.out.println("");

        Object result = proceed();

        popCounter();
        String currentLine3 = String.format("%s --> %s\n", calleClassName, callerClass);

        String currentLine4 = String.format("deactivate %s\n", calleClassName);

        planUMLGrammar = planUMLGrammar + currentLine3 + currentLine4;
        currentMethodStack.pop();

        // System.out.println("<- " + signature.toString());
        // System.out.println("##################END###################");

        return result;
    }
    else{
        Object result = proceed();
        return result;
    }
  }

    private static void appendLineToFile(String line, String filePath){
        try{
            FileWriter fw = new FileWriter(filePath, true); //the true will append the new data
            fw.write(line);//appends the string to the file
            fw.close();
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    private static void createImage(String plantUmlString, String filePath){
        SourceStringReader ssr = new SourceStringReader(plantUmlString);
        try (FileOutputStream imageFile = new FileOutputStream(filePath)) {
            ssr.generateImage(imageFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String updateCounter(){
        Counter aCounter;
        if (counterStack.empty()){
            aCounter = new Counter();
        }
        else{
            aCounter = counterStack.peek().getNextCounter();
        }
        counterStack.push(aCounter);
        return aCounter.toString();
    }

    private static void popCounter(){
        counterStack.pop();
    }
}

// TODO change the name of the file/class
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileWriter;
import java.util.Stack;

import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import net.sourceforge.plantuml.SourceStringReader;

class Counter{
    // TODO check equivalent of __doc__ in Java
    private String base;
    private int count;

    protected Counter(){
        // TODO check syntax to call the other Counter constructor
        this.base = "1";
        this.count = 1;
    }

    protected Counter(String base){
        this.base = base;
        this.count = 1;
    }

    Counter getNextCounter(){
        String newBase;
        if (base == ""){
            newBase = String.valueOf(count);
        }
        else{
            newBase = base + "." + String.valueOf(count);
        }
        count += 1;
        return new Counter(newBase);
    }

    // TODO just for fun want to make this protected,
    // so can i avoid inheritenc from Object?
    public String toString(){
        return base;
    }
}

public aspect SequenceDiagramGenerator{
    // TODO check if aspects can have instance variables
    // need to make these attributes non-static
    static private Stack<String> currentMethodStack= new Stack<String>();
    static private Stack<Counter> counterStack= new Stack<Counter>();
    static private String planUMLGrammar="";
    static private boolean start=true;

    pointcut traceMethods():  call(* *.*(..))   // All methods
                              && !call(* java..*(..)) // Don't want java language inbuilt objects
                              && !within(SequenceDiagramGenerator) // Not within our aspect itself, to avoid infinite reursion
                              && !within(Counter);

    pointcut traceConstructors():  execution(*.new(..)) // All constructors
                                   && !within(SequenceDiagramGenerator)
                                   && !within(Counter);

    pointcut createSeqImage():  execution(* Main.main(..));

    // TODO exploer java.io.PrintStream
    void around(String str) : call(void java.io.PrintStream.println(String))
                                && !within(SequenceDiagramGenerator)
                                && !within(Counter)
                                && args(str){
        planUMLGrammar = planUMLGrammar + "note right : " + str + "\n";
        proceed(str);
    }

    after(): createSeqImage(){
        // start = false;
        String note = "note left of aMain #FFAAAA\n<color #118888>Madhur Khandelwal\nmadhurkhandelwal.234@gmail.com \nend note\n";
        planUMLGrammar = planUMLGrammar + note;
        // System.out.println("_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+");
        // System.out.println("@startuml\n" +
        //           planUMLGrammar +
        //           "\n@enduml");
        // System.out.println("_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+");
        createImage("@startuml\n" +
                  planUMLGrammar +
                  "\n@enduml",
                  "/Users/mak/Downloads/temp/mak.png");
    }

    before(): createSeqImage(){
      start = true;
    }

    before() : traceConstructors() {
        if(start){
            Signature s =
            thisJoinPointStaticPart.getSignature();
            String methodName = s.getName();

            // use "new" for constructors.
            if (methodName.equals("") || methodName.equals("<init>")){
                methodName = "new";
            }

            // TODO show constructors in the sequence diagram
            // System.out.println(s.getDeclaringType().getSimpleName() + "."  + methodName + " {");
        }
    }

    after() : traceConstructors() {
        // if(start){
        //    System.out.println("}");
        // }
    }

    Object around() : traceMethods() {
    if(start){
        // System.out.println("##################START##################");

        MethodSignature signature = (MethodSignature)thisJoinPoint.getSignature();

        String[] parameterNames = signature.getParameterNames();
        Object[] parameterValues = thisJoinPoint.getArgs();

        //String calleClassName = signature.getDeclaringTypeName();
        String calleClassName;
        if (thisJoinPoint.getTarget() == null){
            calleClassName = signature.getDeclaringTypeName();
            // System.out.println("null aaya tha: " + thisJoinPoint.getTarget());
        }
        else{
            // TODO have diff line for objects of same type
            // System.out.println("no null: " + thisJoinPoint.getTarget());
            calleClassName = thisJoinPoint.getTarget().toString().split("@")[0];
        }
        if ("aeiou".indexOf(Character.toLowerCase((calleClassName.charAt(0)))) < 0){
            calleClassName = "a" + calleClassName;
        }
        else{
            calleClassName = "an" + calleClassName;
        }
        // System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
        // System.out.println(calleClassName);
        // System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");
        String calleMethodName = signature.getName();
        String returnTypeName = signature.getReturnType().getName();

        // TODO check any functionality to explore all methods like 'dir' in python
        // maybe use reflection(why such name) API to iterate over the methods and call them
        // System.out.println("thisJoinPoint getArgs  " + thisJoinPoint.getArgs());
        // System.out.println("thisJoinPoint getKind  " + thisJoinPoint.getKind());
        // System.out.println("thisJoinPoint getSignature  " + thisJoinPoint.getSignature());
        // System.out.println("thisJoinPoint getSourceLocation  " + thisJoinPoint.getSourceLocation());
        // System.out.println("thisJoinPoint getStaticPart  " + thisJoinPoint.getStaticPart());
        // System.out.println("thisJoinPoint getTarget  " + thisJoinPoint.getTarget());
        // System.out.println("thisJoinPoint getThis  " + thisJoinPoint.getThis());
        // System.out.println("thisJoinPoint toLongString  " + thisJoinPoint.toLongString());
        // System.out.println("thisJoinPoint toShortString  " + thisJoinPoint.toShortString());
        // System.out.println("thisJoinPoint toString  " + thisJoinPoint.toString());

        // System.out.println("thisJoinPointStaticPart getKind" + thisJoinPointStaticPart.getKind());
        // System.out.println("thisJoinPointStaticPart getSignature" + thisJoinPointStaticPart.getSignature());
        // System.out.println("thisJoinPointStaticPart getSourceLocation" + thisJoinPointStaticPart.getSourceLocation());
        // System.out.println("thisJoinPointStaticPart toLongString" + thisJoinPointStaticPart.toLongString());
        // System.out.println("thisJoinPointStaticPart toShortString" + thisJoinPointStaticPart.toShortString());
        // System.out.println("thisJoinPointStaticPart toString" + thisJoinPointStaticPart.toString()  );

        // System.out.println("thisEnclosingJoinPointStaticPart getKind" + thisEnclosingJoinPointStaticPart.getKind());
        // System.out.println("thisEnclosingJoinPointStaticPart getSignature" + thisEnclosingJoinPointStaticPart.getSignature());
        // System.out.println("thisEnclosingJoinPointStaticPart getSourceLocation" + thisEnclosingJoinPointStaticPart.getSourceLocation());
        // System.out.println("thisEnclosingJoinPointStaticPart toLongString" + thisEnclosingJoinPointStaticPart.toLongString());
        // System.out.println("thisEnclosingJoinPointStaticPart toShortString" + thisEnclosingJoinPointStaticPart.toShortString());
        // System.out.println("thisEnclosingJoinPointStaticPart toString" + thisEnclosingJoinPointStaticPart.toString()  );

        // TODO
        String callerClass="";
        if (!currentMethodStack.empty()){
            callerClass = currentMethodStack.peek();
        }

        int i = 0;
        String argString="";
        for (String x: parameterNames){
            if (argString != ""){
                argString = argString + ",";
            }
            argString = argString + x + ":" + parameterValues[i].getClass().getSimpleName();
            i++;
        }

        // System.out.println("");

        // System.out.println("-> " + signature.toString());
        String currentLine1;
        String countString = updateCounter();
        if (countString != "" ){
            currentLine1 = String.format("%s -> %s: %s : %s(%s): %s\n", callerClass, calleClassName, countString,calleMethodName, argString, returnTypeName);
        }else{
            currentLine1 = String.format("%s -> %s: %s(%s): %s\n", callerClass, calleClassName, calleMethodName, argString, returnTypeName);
        }
        String currentLine2 = String.format("activate %s\n", calleClassName);
        // System.out.println("currentLine1: " + currentLine1);

        planUMLGrammar = planUMLGrammar + currentLine1 + currentLine2;
        currentMethodStack.push(calleClassName);
        for (String x: parameterNames){
            // System.out.print("----------" + x + " ");
        }
        // System.out.println("");

        Object result = proceed();

        popCounter();
        String currentLine3 = String.format("%s --> %s\n", calleClassName, callerClass);

        String currentLine4 = String.format("deactivate %s\n", calleClassName);

        planUMLGrammar = planUMLGrammar + currentLine3 + currentLine4;
        currentMethodStack.pop();

        // System.out.println("<- " + signature.toString());
        // System.out.println("##################END###################");

        return result;
    }
    else{
        Object result = proceed();
        return result;
    }
  }

    private static void appendLineToFile(String line, String filePath){
        try{
            FileWriter fw = new FileWriter(filePath, true); //the true will append the new data
            fw.write(line);//appends the string to the file
            fw.close();
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    private static void createImage(String plantUmlString, String filePath){
        SourceStringReader ssr = new SourceStringReader(plantUmlString);
        try (FileOutputStream imageFile = new FileOutputStream(filePath)) {
            ssr.generateImage(imageFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String updateCounter(){
        Counter aCounter;
        if (counterStack.empty()){
            aCounter = new Counter();
        }
        else{
            aCounter = counterStack.peek().getNextCounter();
        }
        counterStack.push(aCounter);
        return aCounter.toString();
    }

    private static void popCounter(){
        counterStack.pop();
    }
}


XWIKI-5725: Deprecate XWiki#parseMessage
Fix aspect

git-svn-id: d23d7a6431d93e1bdd218a46658458610974b053@33155 f329d543-caf0-0310-9063-dda96c69346f

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 */
package com.xpn.xwiki;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.cache.api.XWikiCache;
import com.xpn.xwiki.cache.api.XWikiCacheService;
import com.xpn.xwiki.cache.api.internal.XWikiCacheServiceStub;
import com.xpn.xwiki.cache.api.internal.XWikiCacheStub;
import com.xpn.xwiki.web.XWikiMessageTool;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Add a backward compatibility layer to the {@link com.xpn.xwiki.XWiki} class.
 *
 * @version $Id$
 */
public privileged aspect XWikiCompatibilityAspect
{
    private static Map XWiki.threadMap = new HashMap();

    /**
     * Transform a text in a URL compatible text
     *
     * @param content text to transform
     * @return encoded result
     * @deprecated replaced by Util#encodeURI since 1.3M2
     */
    @Deprecated
    public String XWiki.getURLEncoded(String content)
    {
        try {
            return URLEncoder.encode(content, this.getEncoding());
        } catch (UnsupportedEncodingException e) {
            return content;
        }
    }

    /**
     * @return true for multi-wiki/false for mono-wiki
     * @deprecated replaced by {@link XWiki#isVirtualMode()} since 1.4M1.
     */
    @Deprecated
    public boolean XWiki.isVirtual()
    {
        return this.isVirtualMode();
    }

    /**
     * @deprecated Removed since it isn't used; since 1.5M1.
     */
    @Deprecated
    public static Map XWiki.getThreadMap()
    {
        return XWiki.threadMap;
    }

    /**
     * @deprecated Removed since it isn't used; since 1.5M1.
     */
    @Deprecated
    public static void XWiki.setThreadMap(Map threadMap)
    {
        XWiki.threadMap = threadMap;
    }

    /**
     * @return the cache service.
     * @deprecated replaced by {@link XWiki#getCacheFactory(XWikiContext)} or
     *             {@link XWiki#getLocalCacheFactory(XWikiContext)} since 1.5M2.
     */
    @Deprecated
    public XWikiCacheService XWiki.getCacheService()
    {
        return new XWikiCacheServiceStub(getCacheFactory(), getLocalCacheFactory());
    }

    /**
     * @deprecated replaced by {@link XWiki#getVirtualWikiCache(XWikiContext)} since 1.5M2.
     */
    @Deprecated
    public XWikiCache XWiki.getVirtualWikiMap()
    {
        return new XWikiCacheStub(this.virtualWikiMap);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpaceCopyright(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebCopyright(XWikiContext context)
    {
        return this.getSpaceCopyright(context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, XWikiContext context)
    {
        return this.getSpacePreference(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, String defaultValue, XWikiContext context)
    {
        return this.getSpacePreference(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, String, String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, String space, String defaultValue, XWikiContext context)
    {
        return this.getSpacePreference(preference, space, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsLong(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public long XWiki.getWebPreferenceAsLong(String preference, XWikiContext context)
    {
        return this.getSpacePreferenceAsLong(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsLong(String, long, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public long XWiki.getWebPreferenceAsLong(String preference, long defaultValue, XWikiContext context)
    {
        return this.getSpacePreferenceAsLong(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsInt(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public int XWiki.getWebPreferenceAsInt(String preference, XWikiContext context)
    {
        return this.getSpacePreferenceAsInt(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsInt(String, int, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public int XWiki.getWebPreferenceAsInt(String preference, int defaultValue, XWikiContext context)
    {
        return this.getSpacePreferenceAsInt(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#copySpaceBetweenWikis(String, String, String, String, XWikiContext)} since
     *             2.3M1
     */
    @Deprecated
    public int XWiki.copyWikiWeb(String space, String sourceWiki, String targetWiki, String language, XWikiContext context)
        throws XWikiException
    {
        return this.copySpaceBetweenWikis(space, sourceWiki, targetWiki, language, context);
    }

    /**
     * @deprecated replaced by
     *             {@link XWiki#copySpaceBetweenWikis(String, String, String, String, boolean, XWikiContext)} since
     *             2.3M1
     */
    @Deprecated
    public int XWiki.copyWikiWeb(String space, String sourceWiki, String targetWiki, String language, boolean clean,
        XWikiContext context) throws XWikiException
    {
        return this.copySpaceBetweenWikis(space, sourceWiki, targetWiki, language, clean, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getDefaultSpace(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getDefaultWeb(XWikiContext context)
    {
        return this.getDefaultSpace(context);
    }

    /**
     * @deprecated replaced by {@link XWiki#skipDefaultSpaceInURLs(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public boolean XWiki.useDefaultWeb(XWikiContext context)
    {
        return this.skipDefaultSpaceInURLs(context);
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.getMessage(String item, XWikiContext context)
    {
        XWikiMessageTool msg = context.getMessageTool();
        if (msg == null) {
            return item;
        } else {
            return msg.get(item);
        }
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.parseMessage(String id, XWikiContext context)
    {
        XWikiMessageTool msg = context.getMessageTool();

        return parseContent(msg.get(id), context);
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.parseMessage(XWikiContext context)
    {
        String message = (String) context.get("message");
        if (message == null) {
            return null;
        }

        return parseMessage(message, context);
    }
}

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 */
package com.xpn.xwiki;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.cache.api.XWikiCache;
import com.xpn.xwiki.cache.api.XWikiCacheService;
import com.xpn.xwiki.cache.api.internal.XWikiCacheServiceStub;
import com.xpn.xwiki.cache.api.internal.XWikiCacheStub;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Add a backward compatibility layer to the {@link com.xpn.xwiki.XWiki} class.
 *
 * @version $Id$
 */
public privileged aspect XWikiCompatibilityAspect
{
    private static Map XWiki.threadMap = new HashMap();

    /**
     * Transform a text in a URL compatible text
     *
     * @param content text to transform
     * @return encoded result
     * @deprecated replaced by Util#encodeURI since 1.3M2
     */
    @Deprecated
    public String XWiki.getURLEncoded(String content)
    {
        try {
            return URLEncoder.encode(content, this.getEncoding());
        } catch (UnsupportedEncodingException e) {
            return content;
        }
    }

    /**
     * @return true for multi-wiki/false for mono-wiki
     * @deprecated replaced by {@link XWiki#isVirtualMode()} since 1.4M1.
     */
    @Deprecated
    public boolean XWiki.isVirtual()
    {
        return this.isVirtualMode();
    }

    /**
     * @deprecated Removed since it isn't used; since 1.5M1.
     */
    @Deprecated
    public static Map XWiki.getThreadMap()
    {
        return XWiki.threadMap;
    }

    /**
     * @deprecated Removed since it isn't used; since 1.5M1.
     */
    @Deprecated
    public static void XWiki.setThreadMap(Map threadMap)
    {
        XWiki.threadMap = threadMap;
    }

    /**
     * @return the cache service.
     * @deprecated replaced by {@link XWiki#getCacheFactory(XWikiContext)} or
     *             {@link XWiki#getLocalCacheFactory(XWikiContext)} since 1.5M2.
     */
    @Deprecated
    public XWikiCacheService XWiki.getCacheService()
    {
        return new XWikiCacheServiceStub(getCacheFactory(), getLocalCacheFactory());
    }

    /**
     * @deprecated replaced by {@link XWiki#getVirtualWikiCache(XWikiContext)} since 1.5M2.
     */
    @Deprecated
    public XWikiCache XWiki.getVirtualWikiMap()
    {
        return new XWikiCacheStub(this.virtualWikiMap);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpaceCopyright(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebCopyright(XWikiContext context)
    {
        return this.getSpaceCopyright(context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, XWikiContext context)
    {
        return this.getSpacePreference(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, String defaultValue, XWikiContext context)
    {
        return this.getSpacePreference(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreference(String, String, String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getWebPreference(String preference, String space, String defaultValue, XWikiContext context)
    {
        return this.getSpacePreference(preference, space, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsLong(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public long XWiki.getWebPreferenceAsLong(String preference, XWikiContext context)
    {
        return this.getSpacePreferenceAsLong(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsLong(String, long, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public long XWiki.getWebPreferenceAsLong(String preference, long defaultValue, XWikiContext context)
    {
        return this.getSpacePreferenceAsLong(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsInt(String, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public int XWiki.getWebPreferenceAsInt(String preference, XWikiContext context)
    {
        return this.getSpacePreferenceAsInt(preference, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getSpacePreferenceAsInt(String, int, XWikiContext)} since 2.3M1
     */
    @Deprecated
    public int XWiki.getWebPreferenceAsInt(String preference, int defaultValue, XWikiContext context)
    {
        return this.getSpacePreferenceAsInt(preference, defaultValue, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#copySpaceBetweenWikis(String, String, String, String, XWikiContext)} since
     *             2.3M1
     */
    @Deprecated
    public int XWiki.copyWikiWeb(String space, String sourceWiki, String targetWiki, String language, XWikiContext context)
        throws XWikiException
    {
        return this.copySpaceBetweenWikis(space, sourceWiki, targetWiki, language, context);
    }

    /**
     * @deprecated replaced by
     *             {@link XWiki#copySpaceBetweenWikis(String, String, String, String, boolean, XWikiContext)} since
     *             2.3M1
     */
    @Deprecated
    public int XWiki.copyWikiWeb(String space, String sourceWiki, String targetWiki, String language, boolean clean,
        XWikiContext context) throws XWikiException
    {
        return this.copySpaceBetweenWikis(space, sourceWiki, targetWiki, language, clean, context);
    }

    /**
     * @deprecated replaced by {@link XWiki#getDefaultSpace(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public String XWiki.getDefaultWeb(XWikiContext context)
    {
        return this.getDefaultSpace(context);
    }

    /**
     * @deprecated replaced by {@link XWiki#skipDefaultSpaceInURLs(XWikiContext)} since 2.3M1
     */
    @Deprecated
    public boolean XWiki.useDefaultWeb(XWikiContext context)
    {
        return this.skipDefaultSpaceInURLs(context);
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.getMessage(String item, XWikiContext context)
    {
        XWikiMessageTool msg = context.getMessageTool();
        if (msg == null) {
            return item;
        } else {
            return msg.get(item);
        }
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.parseMessage(String id, XWikiContext context)
    {
        XWikiMessageTool msg = context.getMessageTool();

        return parseContent(msg.get(id), context);
    }

    /**
     * @deprecated use {@link XWikiMessageTool#get(String, List)} instead. You can access message tool using
     *             {@link XWikiContext#getMessageTool()}.
     */
    @Deprecated
    public String XWiki.parseMessage(XWikiContext context)
    {
        String message = (String) context.get("message");
        if (message == null) {
            return null;
        }

        return parseMessage(message, context);
    }
}


write statistics to file

write statistics to file

package com.mebigfatguy.hashshmash;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.Signature;

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map m): call(HashMap.new(..)) {
        Signature sig = thisJoinPointStaticPart.getSignature();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, System.currentTimeMillis(), sig + ":" + line);
        journaller.add(details);
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 10 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashMapDetails, HashMapDetails> hmDetails = new ConcurrentHashMap<HashMapDetails, HashMapDetails>();
    private PrintWriter writer;

    public Journaller() {
        try {
            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

            File dir = new File(System.getProperty("user.home"), ".hashshmash");
            dir.mkdirs();

            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, new Date().toString() + ".txt")))));

            Thread t = new Thread(this);
            t.setDaemon(true);
            t.start();
        } catch (Exception e) {
        }
    }

    public void add(HashMapDetails details) {
        hmDetails.put(details,  details);
    }

    public void run() {
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(SLEEP_TIME);

                for (HashMapDetails details : hmDetails.keySet()) {
                    try {
                        if (details.map != null) {
                            int newSize = details.map.size();
                            if (newSize == details.size) {
                                Entry<?, ?>[] table = (Entry<?, ?>[])tableField.get(details.map);
                                details.totalSlots = table.length;
                                for (Entry<?, ?> e : table) {
                                    if (e != null) {
                                        details.usedSlots++;
                                    }
                                }
                                writer.println(details.allocTime + "\t" + details.caller + "\t" + details.map.size() + "\t" + details.totalSlots + "\t" + details.usedSlots);
                                hmDetails.remove(details);
                            }
                        }
                    } catch (Exception e) {
                        //might get ConcurrentModificationException or such, just ignore
                    }
                }
                writer.flush();
            }
        } catch (InterruptedException ie) {
        }
    }
}

class HashMapDetails {
    public Map<?, ?> map;
    public long allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public HashMapDetails(Map<?, ?> m, long t, String c) {
        map = m;
        allocTime = t;
        caller = c;
        size = map.size();
    }
}

package com.mebigfatguy.hashshmash;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.aspectj.lang.Signature;

public aspect HashCollector {

    private static final int SLEEP_TIME = 10 * 1000;
    private static Field TABLE_FIELD;
    private static ConcurrentHashMap<HashMapDetails, HashMapDetails> HM_DETAILS = new ConcurrentHashMap<HashMapDetails, HashMapDetails>();

    static {
        try {
            TABLE_FIELD = HashMap.class.getDeclaredField("table");
            TABLE_FIELD.setAccessible(true);

            Thread t = new Thread(new Runnable() {
                public void run() {
                    try {
                        while (!Thread.interrupted()) {
                            Thread.sleep(SLEEP_TIME);

                            for (HashMapDetails details : HM_DETAILS.keySet()) {
                                try {
                                    if (details.map != null) {
                                        int newSize = details.map.size();
                                        if (newSize == details.size) {
                                            Entry<?, ?>[] table = (Entry<?, ?>[])TABLE_FIELD.get(details.map);
                                            details.totalSlots = table.length;
                                            for (Entry<?, ?> e : table) {
                                                if (e != null) {
                                                    details.usedSlots++;
                                                }
                                            }
                                            details.map = null;
                                        }
                                    }
                                } catch (Exception e) {
                                    //might get ConcurrentModificationException or such, just ignore
                                }
                            }
                        }
                    } catch (InterruptedException ie) {
                    }
                }
            });
            t.setDaemon(true);
            t.start();
        } catch (Exception e) {

        }
    }

    after() returning (Map m): call(HashMap.new(..)) {
        Signature sig = thisJoinPointStaticPart.getSignature();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, System.currentTimeMillis(), sig + ":" + line);
        HM_DETAILS.put(details,  details);
    }

    class HashMapDetails {
        public HashMapDetails(Map<?, ?> m, long t, String c) {
            map = m;
            allocTime = t;
            caller = c;
            size = map.size();
        }

        public Map<?, ?> map;
        public long allocTime;
        public String caller;
        public int size;
        public int usedSlots;
        public int totalSlots;
    }
}


removed failed experiments

removed failed experiments

/*
 * Copyright (c) 2013 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.eigengo.monitor.agent.akka;

import akka.actor.*;
import org.eigengo.monitor.agent.AgentConfiguration;
import org.eigengo.monitor.output.CounterInterface;
import scala.Option;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Contains advices for monitoring behaviour of an actor; typically imprisoned in an {@code ActorCell}.
 */
public aspect ActorCellMonitoringAspect extends AbstractMonitoringAspect issingleton() {
    private AkkaAgentConfiguration agentConfiguration;
    private final CounterInterface counterInterface;
    private final Option<String> anonymousActorClassName = Option.empty();
    private final ConcurrentHashMap<PathAndClass, AtomicLong> samplingCounters  = new ConcurrentHashMap<PathAndClass, AtomicLong>();
    private final ConcurrentHashMap<PathAndClass, AtomicInteger> numberOfActors = new ConcurrentHashMap<PathAndClass, AtomicInteger>();

    /**
     * Constructs this aspect
     */
    public ActorCellMonitoringAspect() {
        AgentConfiguration<AkkaAgentConfiguration> configuration = getAgentConfiguration("akka", AkkaAgentConfigurationJapi.apply());
        this.agentConfiguration = configuration.agent();
        this.counterInterface = createCounterInterface(configuration.common());
    }

    /**
     * Advises the {@code ActorCell.receiveMessage(message: Object): Unit}
     * We proceed with the pointcut if the actor is to be included in the monitoring *and* this is
     * the 'multiple-of-n'th time we've seen a message for an actor with a sample rate of n.
     *
     * Currently, we sample queue size, the fact that the message is delivered, the simple name of the class of the
     * message, and the time taken to complete the actor's reactive action.
     *
     * @param actorCell the ActorCell where the actor that receives the message "lives"
     * @param msg the incoming message
     */
    Object around(ActorCell actorCell, Object msg) : Pointcuts.actorCellReceiveMessage(actorCell, msg) {
        final ActorPath actorPath = actorCell.self().path();
        final PathAndClass pathAndClass = new PathAndClass(actorPath, getActorClassName(actorCell));
        if (!includeActorPath(pathAndClass) || !sampleMessage(pathAndClass)) return proceed(actorCell, msg);

        int samplingRate = getSampleRate(pathAndClass);

        // we tag by actor name
        final String[] tags = getTags(actorPath, getActorClassName(actorCell));

        // record the queue size
        this.counterInterface.recordGaugeValue(Aspects.queueSize(), actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter(Aspects.delivered(), samplingRate, tags);
        this.counterInterface.incrementCounter(Aspects.delivered(msg), samplingRate, tags);

        // measure the time. we're using the ``nanoTime`` call to access the high-precision timer.
        // since we're not really interested in wall time, but just some increasing measure of
        // elapsed time
        Object result = null;
        final long start = System.nanoTime();
        // result will always be ``null``, because target returns ``Unit``
        result = proceed(actorCell, msg);
        // ns or µs is too fine. ms will do for now.
        final long duration = (System.nanoTime() - start) / 1000000;

        // record the actor duration
        this.counterInterface.recordExecutionTime(Aspects.actorDuration(), (int)duration, tags);

        // return null would do the trick, but we want to be _proper_.
        return result;
    }

    /**
     * Advises the {@code ActorCell.handleInvokeFailure(_, failure: Throwable): Unit}
     *
     * @param actorCell the ActorCell where the error spreads from
     * @param failure the exception that escaped from the {@code receive} method
     */
    before(ActorCell actorCell, Throwable failure) : Pointcuts.actorCellHandleInvokeFailure(actorCell, failure) {
        // record the error, general and specific
        String[] tags = getTags(actorCell.self().path(), getActorClassName(actorCell));
        this.counterInterface.incrementCounter(Aspects.actorError(), tags);
        this.counterInterface.incrementCounter(Aspects.actorError(failure), tags);
    }

    /**
     * Advises the {@code EventStream.publish(event: Any): Unit}
     *
     * @param event the received event
     */
    before(Object event) : Pointcuts.eventStreamPublish(event) {
        if (event instanceof UnhandledMessage) {
            UnhandledMessage unhandledMessage = (UnhandledMessage)event;
            String[] tags = getTags(unhandledMessage.recipient().path(), this.anonymousActorClassName);
            this.counterInterface.incrementCounter(Aspects.undelivered(), tags);
            this.counterInterface.incrementCounter(Aspects.undelivered(unhandledMessage.getMessage()), tags);
        }
    }

    /**
     * Advises the {@code actorOf} method of {@code ActorRefFactory} implementations
     *
     * @param props the {@code Props} instance used in the call
     * @param actor the {@code ActorRef} returned from the call
     */
    after(Props props) returning (ActorRef actor) : Pointcuts.anyActorOf(props) {
        recordActorCount(actor.path(), props, CountType.Increment);
    }

    /**
     * Advises the {@code LocalActorRef.stop} method
     *
     * @param actorCell the {@code ActorCell} of the actor being stopped
     */
    after(ActorCell actorCell) : Pointcuts.actorCellInternalStop(actorCell) {
        recordActorCount(actorCell.self().path(), actorCell.props(), CountType.Decrement);
    }

    /**
     * Records the actor count increment or decrement
     *
     * @param path the ActorPath being created or destroyed
     * @param props the Props of the actor at the {@code path}
     * @param countType the increment or decrement
     */
     private void recordActorCount(ActorPath path, Props props, CountType countType) {
         final PathAndClass pac = new PathAndClass(path, getActorClassName(props));
         if (!includeActorPath(pac)) return;

         final String[] tags = getTags(path, pac.actorClassName());
         this.numberOfActors.putIfAbsent(pac, new AtomicInteger(0));
         // increment and get the current number of actors of this type (if the value was 0, then this returns 1 -- which is correct)
         final int currentNumberOfActors;
         switch (countType) {
             case Increment:
                 currentNumberOfActors = this.numberOfActors.get(pac).incrementAndGet();
                 break;
             case Decrement:
                 currentNumberOfActors = this.numberOfActors.get(pac).decrementAndGet();
                 break;
             default:
                 currentNumberOfActors = 0;
                 break;
         }

         this.counterInterface.recordGaugeValue(Aspects.actorCount(), currentNumberOfActors, tags);
     }

    /**
     * Injects the new {@code AkkaAgentConfiguration} instance.
     *
     * @param agentConfiguration the new configuration
     */
    synchronized final void setAgentConfiguration(AkkaAgentConfiguration agentConfiguration) {
        this.agentConfiguration = agentConfiguration;
    }

    /**
     * The count type for exhaustive matching
     */
    private static enum CountType {
        Increment, Decrement
    }

    /**
     * Decide whether to include this ActorCell in our measurements
     *
     * @param pathAndClass the PAC container
     * @return whether to include the given actor in the metrics
     */
    private boolean includeActorPath(final PathAndClass pathAndClass) {
        // do not monitor our own output code
        if (pathAndClass.actorClassName().isDefined()) {
            if (pathAndClass.actorClassName().get().startsWith("org.eigengo.monitor.output")) return false;
        }

        // include actor if it's in 'included' list
        if (this.agentConfiguration.included().accept(pathAndClass)) return true;
        // exclude actor if excluded (i.e. is in 'excluded' list, or excludeAllNotIncluded = true, and actor is not included)
        if (this.agentConfiguration.excluded().accept(pathAndClass)) return false;

        // skip system actor checks if we wish to monitor them
        if (this.agentConfiguration.includeSystemAgents()) return true;

        String userOrSystem = pathAndClass.actorPath().getElements().iterator().next();
        return "user".equals(userOrSystem);
    }

    /**
     * Lookup the sample rate for an actor from the configuration
     *
     * @param pathAndClass the PAC container
     * @return the sampling rate as non-negative integer
     */
    private int getSampleRate(final PathAndClass pathAndClass) {
        return this.agentConfiguration.sampling().getRate(pathAndClass);
    }

    /**
     * Decide whether to sample an actor on a particular occasion
     *
     * @param pathAndClass the PAC container
     * @return {@code true} if we should sample this actor
     */
    private boolean sampleMessage(final PathAndClass pathAndClass) {
        int sampleRate = getSampleRate(pathAndClass);
        if (sampleRate == 1) return true;

        this.samplingCounters.putIfAbsent(pathAndClass, new AtomicLong(0));
        long timesSeenSoFar = this.samplingCounters.get(pathAndClass).incrementAndGet();

        return (timesSeenSoFar % sampleRate == 1); // == 1 to log first value (incrementAndGet returns updated value)
    }

    /**
     * Formats the given {@code path} in a way that can be used for tagging. For example, for
     * path akka://default/user/a/b/c, it returns akka.path:/default/user/a/b/c
     *
     * @param path the path
     * @return the tag-ready path
     */
    private String actorPathToString(ActorPath path) {
        StringBuilder sb = new StringBuilder();
        sb.append("akka.path:/");
        sb.append(path.address().system());
        for (String element : path.getElements()) {
            sb.append("/");
            sb.append(element);
        }
        return sb.toString();
    }

    /**
     * Decides whether {@code path} represents the "root" of the user actors
     *
     * @param path the actor path
     * @return {@code true} if root of user actors
     */
    private boolean isUserRoot(ActorPath path) {
        return "user".equals(path.elements().mkString("/"));
    }

    /**
     * Computes the tags for the given {@code actorPath} and {@code actor} instances.
     *
     * @param actorPath the actor path; never {@code null}
     * @param actorClassName the actor instance; may be {@code null}
     * @return non-{@code null} array of tags
     */
    private String[] getTags(final ActorPath actorPath, final Option<String> actorClassName) {
        List<String> tags = new ArrayList<String>();

        // TODO: Improve detection of routed actors. This only detects "root" unnamed actors
        String lastPathElement = actorPath.elements().last();
        if (lastPathElement.startsWith("$")) {
            // this is routed actor.
            final ActorPath parent = actorPath.parent();
            if (isUserRoot(parent)) {
                // the parent is akka://xxx/user
                tags.add(actorPathToString(actorPath));
            } else {
                // the parent is some other actor, akka://xxx/user/foo
                tags.add(actorPathToString(parent));
                if (this.agentConfiguration.includeRoutees()) tags.add(actorPathToString(actorPath));
            }
        } else {
            // there is no supervisor
            tags.add(actorPathToString(actorPath));
        }
        if (actorClassName.isDefined()) {
            tags.add(String.format("akka.type:%s.%s", actorPath.address().system(), actorClassName.get()));
        }

        return tags.toArray(new String[tags.size()]);
    }

    /**
     * returns the canonical name of the actor type associated with an ActorCell
     *
     * @param actorCell the actor cell to get the name for
     * @return the Option of actor class, never {@code null}.
     */
    private Option<String> getActorClassName(final ActorCell actorCell) {
        return getActorClassName(actorCell.props());
    }

    /**
     * Returns the canonical name of the actor type associated with a Props instance
     *
     * Returns null if props.actorClass does not have a canonical name (i.e., if
     * it is a local or anonymous class)
     *
     * Notably, when the actor class is anonymous, the {@code getCanonicalName} returns {@code null},
     * which we deal with here.
     *
     * @param props the ActorRef {@code Props} instance
     * @return the Option of actor class, never {@code null}.
     */
    private Option<String> getActorClassName(final Props props) {
        final String canonicalName = props.actorClass().getCanonicalName();
        if (canonicalName == null) return this.anonymousActorClassName;

        return Option.apply(canonicalName);
    }

}

/*
 * Copyright (c) 2013 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.eigengo.monitor.agent.akka;

import akka.actor.*;
import org.eigengo.monitor.agent.AgentConfiguration;
import org.eigengo.monitor.output.CounterInterface;
import scala.Option;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Contains advices for monitoring behaviour of an actor; typically imprisoned in an {@code ActorCell}.
 */
public aspect ActorCellMonitoringAspect extends AbstractMonitoringAspect issingleton() {
    private AkkaAgentConfiguration agentConfiguration;
    private final CounterInterface counterInterface;
    private final Option<String> anonymousActorClassName = Option.empty();
    private final ConcurrentHashMap<PathAndClass, AtomicLong> samplingCounters  = new ConcurrentHashMap<PathAndClass, AtomicLong>();
    private final ConcurrentHashMap<PathAndClass, AtomicInteger> numberOfActors = new ConcurrentHashMap<PathAndClass, AtomicInteger>();
    private final ConcurrentHashMap<ActorPath, String> pathToClass              = new ConcurrentHashMap<ActorPath, String>();

    /**
     * Constructs this aspect
     */
    public ActorCellMonitoringAspect() {
        AgentConfiguration<AkkaAgentConfiguration> configuration = getAgentConfiguration("akka", AkkaAgentConfigurationJapi.apply());
        this.agentConfiguration = configuration.agent();
        this.counterInterface = createCounterInterface(configuration.common());
    }

    /**
     * Advises the {@code ActorCell.receiveMessage(message: Object): Unit}
     * We proceed with the pointcut if the actor is to be included in the monitoring *and* this is
     * the 'multiple-of-n'th time we've seen a message for an actor with a sample rate of n.
     *
     * Currently, we sample queue size, the fact that the message is delivered, the simple name of the class of the
     * message, and the time taken to complete the actor's reactive action.
     *
     * @param actorCell the ActorCell where the actor that receives the message "lives"
     * @param msg the incoming message
     */
    Object around(ActorCell actorCell, Object msg) : Pointcuts.actorCellReceiveMessage(actorCell, msg) {
        final ActorPath actorPath = actorCell.self().path();
        final PathAndClass pathAndClass = new PathAndClass(actorPath, getActorClassName(actorCell));
        if (!includeActorPath(pathAndClass) || !sampleMessage(pathAndClass)) return proceed(actorCell, msg);

        int samplingRate = getSampleRate(pathAndClass);

        // we tag by actor name
        final String[] tags = getTags(actorPath, getActorClassName(actorCell));

        // record the queue size
        this.counterInterface.recordGaugeValue(Aspects.queueSize(), actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter(Aspects.delivered(), samplingRate, tags);
        this.counterInterface.incrementCounter(Aspects.delivered(msg), samplingRate, tags);

        // measure the time. we're using the ``nanoTime`` call to access the high-precision timer.
        // since we're not really interested in wall time, but just some increasing measure of
        // elapsed time
        Object result = null;
        final long start = System.nanoTime();
        // result will always be ``null``, because target returns ``Unit``
        result = proceed(actorCell, msg);
        // ns or µs is too fine. ms will do for now.
        final long duration = (System.nanoTime() - start) / 1000000;

        // record the actor duration
        this.counterInterface.recordExecutionTime(Aspects.actorDuration(), (int)duration, tags);

        // return null would do the trick, but we want to be _proper_.
        return result;
    }

    /**
     * Advises the {@code ActorCell.handleInvokeFailure(_, failure: Throwable): Unit}
     *
     * @param actorCell the ActorCell where the error spreads from
     * @param failure the exception that escaped from the {@code receive} method
     */
    before(ActorCell actorCell, Throwable failure) : Pointcuts.actorCellHandleInvokeFailure(actorCell, failure) {
        // record the error, general and specific
        String[] tags = getTags(actorCell.self().path(), getActorClassName(actorCell));
        this.counterInterface.incrementCounter(Aspects.actorError(), tags);
        this.counterInterface.incrementCounter(Aspects.actorError(failure), tags);
    }

    /**
     * Advises the {@code EventStream.publish(event: Any): Unit}
     *
     * @param event the received event
     */
    before(Object event) : Pointcuts.eventStreamPublish(event) {
        if (event instanceof UnhandledMessage) {
            UnhandledMessage unhandledMessage = (UnhandledMessage)event;
            String[] tags = getTags(unhandledMessage.recipient().path(), this.anonymousActorClassName);
            this.counterInterface.incrementCounter(Aspects.undelivered(), tags);
            this.counterInterface.incrementCounter(Aspects.undelivered(unhandledMessage.getMessage()), tags);
        }
    }

    /**
     * Advises the {@code actorOf} method of {@code ActorRefFactory} implementations
     *
     * @param props the {@code Props} instance used in the call
     * @param actor the {@code ActorRef} returned from the call
     */
    after(Props props) returning (ActorRef actor) : Pointcuts.anyActorOf(props) {
        recordActorCount(actor.path(), props, CountType.Increment);
    }

    /**
     * Advises the {@code LocalActorRef.stop} method
     *
     * @param actorCell the {@code ActorCell} of the actor being stopped
     */
    after(ActorCell actorCell) : Pointcuts.actorCellInternalStop(actorCell) {
        recordActorCount(actorCell.self().path(), actorCell.props(), CountType.Decrement);
    }

    /**
     * Records the actor count increment or decrement
     *
     * @param path the ActorPath being created or destroyed
     * @param props the Props of the actor at the {@code path}
     * @param countType the increment or decrement
     */
     private void recordActorCount(ActorPath path, Props props, CountType countType) {
         final PathAndClass pac = new PathAndClass(path, getActorClassName(props));
         if (!includeActorPath(pac)) return;

         final String[] tags = getTags(path, pac.actorClassName());
         this.numberOfActors.putIfAbsent(pac, new AtomicInteger(0));
         // increment and get the current number of actors of this type (if the value was 0, then this returns 1 -- which is correct)
         final int currentNumberOfActors;
         switch (countType) {
             case Increment:
                 currentNumberOfActors = this.numberOfActors.get(pac).incrementAndGet();
                 break;
             case Decrement:
                 currentNumberOfActors = this.numberOfActors.get(pac).decrementAndGet();
                 break;
             default:
                 currentNumberOfActors = 0;
                 break;
         }

         this.counterInterface.recordGaugeValue(Aspects.actorCount(), currentNumberOfActors, tags);
     }

    /**
     * Injects the new {@code AkkaAgentConfiguration} instance.
     *
     * @param agentConfiguration the new configuration
     */
    synchronized final void setAgentConfiguration(AkkaAgentConfiguration agentConfiguration) {
        this.agentConfiguration = agentConfiguration;
    }

    /**
     * The count type for exhaustive matching
     */
    private static enum CountType {
        Increment, Decrement
    }

    /**
     * Decide whether to include this ActorCell in our measurements
     *
     * @param pathAndClass the PAC container
     * @return whether to include the given actor in the metrics
     */
    private boolean includeActorPath(final PathAndClass pathAndClass) {
        // do not monitor our own output code
        if (pathAndClass.actorClassName().isDefined()) {
            if (pathAndClass.actorClassName().get().startsWith("org.eigengo.monitor.output")) return false;
        }

        // include actor if it's in 'included' list
        if (this.agentConfiguration.included().accept(pathAndClass)) return true;
        // exclude actor if excluded (i.e. is in 'excluded' list, or excludeAllNotIncluded = true, and actor is not included)
        if (this.agentConfiguration.excluded().accept(pathAndClass)) return false;

        // skip system actor checks if we wish to monitor them
        if (this.agentConfiguration.includeSystemAgents()) return true;

        String userOrSystem = pathAndClass.actorPath().getElements().iterator().next();
        return "user".equals(userOrSystem);
    }

    /**
     * Lookup the sample rate for an actor from the configuration
     *
     * @param pathAndClass the PAC container
     * @return the sampling rate as non-negative integer
     */
    private int getSampleRate(final PathAndClass pathAndClass) {
        return this.agentConfiguration.sampling().getRate(pathAndClass);
    }

    /**
     * Decide whether to sample an actor on a particular occasion
     *
     * @param pathAndClass the PAC container
     * @return {@code true} if we should sample this actor
     */
    private boolean sampleMessage(final PathAndClass pathAndClass) {
        int sampleRate = getSampleRate(pathAndClass);
        if (sampleRate == 1) return true;

        this.samplingCounters.putIfAbsent(pathAndClass, new AtomicLong(0));
        long timesSeenSoFar = this.samplingCounters.get(pathAndClass).incrementAndGet();
        // yeah yeah. Put it somewhere else. Why?
        if (timesSeenSoFar == 1 && pathAndClass.actorClassName() != this.anonymousActorClassName) {
            pathToClass.putIfAbsent(pathAndClass.actorPath(), pathAndClass.actorClassName().get());
        }
        if (sampleRate == 1) return true;
        return (timesSeenSoFar % sampleRate == 1); // == 1 to log first value (incrementAndGet returns updated value)
    }

    /**
     * Formats the given {@code path} in a way that can be used for tagging. For example, for
     * path akka://default/user/a/b/c, it returns akka.path:/default/user/a/b/c
     *
     * @param path the path
     * @return the tag-ready path
     */
    private String actorPathToString(ActorPath path) {
        StringBuilder sb = new StringBuilder();
        sb.append("akka.path:/");
        sb.append(path.address().system());
        for (String element : path.getElements()) {
            sb.append("/");
            sb.append(element);
        }
        return sb.toString();
    }

    /**
     * Decides whether {@code path} represents the "root" of the user actors
     *
     * @param path the actor path
     * @return {@code true} if root of user actors
     */
    private boolean isUserRoot(ActorPath path) {
        return "user".equals(path.elements().mkString("/"));
    }

    /**
     * Computes the tags for the given {@code actorPath} and {@code actor} instances.
     *
     * @param actorPath the actor path; never {@code null}
     * @param actorClassName the actor instance; may be {@code null}
     * @return non-{@code null} array of tags
     */
    private String[] getTags(final ActorPath actorPath, final Option<String> actorClassName) {
        List<String> tags = new ArrayList<String>();

        // TODO: Improve detection of routed actors. This only detects "root" unnamed actors
        String lastPathElement = actorPath.elements().last();
        if (lastPathElement.startsWith("$")) {
            // this is routed actor.
            final ActorPath parent = actorPath.parent();
            if (isUserRoot(parent)) {
                // the parent is akka://xxx/user
                tags.add(actorPathToString(actorPath));
            } else {
                // the parent is some other actor, akka://xxx/user/foo
                tags.add(actorPathToString(parent));
                if (this.agentConfiguration.includeRoutees()) tags.add(actorPathToString(actorPath));
            }
        } else {
            // there is no supervisor
            tags.add(actorPathToString(actorPath));
        }
        if (actorClassName.isDefined()) {
            tags.add(String.format("akka.type:%s.%s", actorPath.address().system(), actorClassName.get()));
        } else if (pathToClass.contains(actorPath)) {
            tags.add(String.format("akka.type:%s.%s", actorPath.address().system(), pathToClass.get(actorPath)));
        }

        return tags.toArray(new String[tags.size()]);
    }

    /**
     * returns the canonical name of the actor type associated with an ActorCell
     *
     * @param actorCell the actor cell to get the name for
     * @return the Option of actor class, never {@code null}.
     */
    private Option<String> getActorClassName(final ActorCell actorCell) {
        return getActorClassName(actorCell.props());
    }

    /**
     * Returns the canonical name of the actor type associated with a Props instance
     *
     * Returns null if props.actorClass does not have a canonical name (i.e., if
     * it is a local or anonymous class)
     *
     * Notably, when the actor class is anonymous, the {@code getCanonicalName} returns {@code null},
     * which we deal with here.
     *
     * @param props the ActorRef {@code Props} instance
     * @return the Option of actor class, never {@code null}.
     */
    private Option<String> getActorClassName(final Props props) {
        final String canonicalName = props.actorClass().getCanonicalName();
        if (canonicalName == null) return this.anonymousActorClassName;

//        final Class<?> something = props.clazz();
//        Class<?> interim = props.actorClass();
//        System.out.println("##@ 0 : "+something.toString());
//        System.out.println("##@ 1 : "+interim.getDeclaredClasses().length);
//        System.out.println("##@ 1 : "+interim);
//        for (int i = 0; i < interim.getDeclaredClasses().length; i++) {
//            System.out.println("##@ "+(i+2)+" : "+interim.getDeclaredClasses()[i].toString());
//        }

//        for (int i=0; i <something.getTypeParameters().length; i++) {
//            System.out.println("##@ 1 : "+something.getTypeParameters()[i]);
//        }
//        System.out.println("# 2 : "+something.getClasses());
//        for (Class<?> i : something.getClasses()) {
//            System.out.println("##@ 2 : "+i);
//        }
//        System.out.println("##@ 3 : "+something.getComponentType());
//        System.out.println("# 4 : "+something.getInterfaces());
//        for (Class<?> i : something.getInterfaces()) {
//            System.out.println("##@ 4 : "+i);
//        }

        return Option.apply(canonicalName);
    }

}


Remove annotation to remove java5 dependency

git-svn-id: 7acc490bd371dbc82047a939b87dc892fdc31f59@22179 76a6fc44-f60b-0410-a9a8-e67b0e8fc65c

package org.lamport.tla.toolbox.test.threading;

import org.aspectj.lang.annotation.SuppressAjWarnings;

/**
 * The purpose of this advice is to intercept method execution in the backend
 * code - namely all code in the packages tlc2, tla2sany, tla2tex, pcal and util.
 *
 * It notifies the {@link MonitorAdaptor} about the method execution.
 */
public aspect MonitorAspect {

	public MonitorAspect() {
		MonitorAdaptor.setAspect(this);
	}

	// known places where backend call within UI thread are acceptable
	pointcut inFilter() :
		withincode(public boolean org.lamport.tla.toolbox.util.ResourceHelper.isValidSpecName(String));

	// catch all method calls (static and object ones)
	pointcut callToBackend() :
		   execution(* tlc2..*.*(..))
		|| execution(* tla2sany..*.*(..))
		|| execution(* tla2tex..*.*(..))
		|| execution(* pcal..*.*(..))
		|| execution(* util..*.*(..));

	// capture calls to backend, but not within ourself or in filter
	before(): (callToBackend()
			&& !cflowbelow(callToBackend()) && !cflowbelow(inFilter())) {
		MonitorAdaptor.enter(thisJoinPoint);
	}
}

package org.lamport.tla.toolbox.test.threading;

import org.aspectj.lang.annotation.SuppressAjWarnings;

/**
 * The purpose of this advice is to intercept method execution in the backend
 * code - namely all code in the packages tlc2, tla2sany, tla2tex, pcal and util.
 *
 * It notifies the {@link MonitorAdaptor} about the method execution.
 */
public aspect MonitorAspect {

	public MonitorAspect() {
		MonitorAdaptor.setAspect(this);
	}

	// known places where backend call within UI thread are acceptable
	pointcut inFilter() :
		withincode(public boolean org.lamport.tla.toolbox.util.ResourceHelper.isValidSpecName(String));

	// catch all method calls (static and object ones)
	pointcut callToBackend() :
		   execution(* tlc2..*.*(..))
		|| execution(* tla2sany..*.*(..))
		|| execution(* tla2tex..*.*(..))
		|| execution(* pcal..*.*(..))
		|| execution(* util..*.*(..));

	// capture calls to backend, but not within ourself or in filter
	@SuppressAjWarnings
	before(): (callToBackend()
			&& !cflowbelow(callToBackend()) && !cflowbelow(inFilter())) {
		MonitorAdaptor.enter(thisJoinPoint);
	}
}