bug - fixed inheritance not working right for ltw (had to also provide sys_ pointcuts)

package org.automon.aspects;

import org.automon.implementations.NullImp;
import org.automon.implementations.OpenMon;

/**
 *
Aspect that advises the {@link org.aspectj.lang.annotation.Around} and {@link org.aspectj.lang.annotation.AfterThrowing} annotations.
 * The appropriate methods on {@link org.automon.implementations.OpenMon} methods are called. The advice typically times methods
 * and counts any exceptions  thrown however other behavior such as logging is also possible.

 *
 *
Note a developer should implement and provide any methods for this class or {@link org.automon.aspects.AspectJBase} or
 * {@link org.automon.aspects.SpringBase}.

 *
 *
Note: I used native aspect style instead of the @AspectJ style because around in @AspectJ style doesn't seem to allow for the
 * more performant use of the static part of the JoinPoint. The static part only seems to be available without first
 * creating the dynamic JoinPoint in native aspects. Native style aspects are more powerful and can later be extended by developers
 * with @AspectJ style, so it is probably the best option anyway.

 */
public abstract aspect AutomonAspect  {
    private OpenMon openMon = new NullImp();
    protected  boolean enable = true;

    public boolean isEnabled() {
        return enable;
    }

    public void enable(boolean shouldEnable) {
        enable = shouldEnable;
    }

    /**
     * monitor() advice - Wraps the given pointcut and calls the appropriate {@link org.automon.implementations.OpenMon} method at the beginning and end
     * of the method call.
     *
     * @return The advised methods value or void.
     * @throws Throwable If the method throws a {@link java.lang.Throwable} the advice will rethrow it.
     */
    Object around() throws Throwable : monitor()  {
        // Note: context is typically a Timer/Monitor object returned by the monitoring implementation (Jamon, JavaSimon, Metrics,...)
        // though to this advice it is simply an object and the advice doesn't care what the intent of the context/object is.
        Object context = openMon.start(thisJoinPointStaticPart);
        try {
            Object retVal = proceed();
            openMon.stop(context);
            return retVal;
        } catch (Throwable throwable) {
            openMon.stop(context, throwable);
            throw throwable;
        }
    }

    /**
     * exceptions() advice - Takes action on any Exception thrown.  It Tracks/Counts any exceptions thrown by the pointcut.
     */
    after() throwing(Throwable throwable): exceptions() {
        openMon.exception(thisJoinPoint, throwable);
    }

    /** Retreive monitoring implementation */
    public OpenMon getOpenMon() {
        return openMon;
    }

    /** Set monitoring implementation such as JAMon, Metrics, or JavaSimon */
    public void setOpenMon(OpenMon openMon) {
        this.openMon = openMon;
    }

    /** pointcut that determines what is monitored for performance/time */
    public pointcut monitor() : user_monitor() && sys_monitor();

    /** User should implement this pointcut to determine what should be monitored for performance/time */
    public abstract pointcut user_monitor();

    /** reserved pointcut for Automon team */
    public pointcut sys_monitor();

    /** pointcut that determines what is monitored for exceptions.  It can be the same as the {@link #monitor()} poincut */
    public pointcut exceptions() : user_exceptions() && sys_exceptions();

    /** User should implement this pointcut to determine what should be monitored for performance/time */
    public abstract pointcut user_exceptions();

    /** reserved pointcut for Automon team */
    public  pointcut sys_exceptions();

}

package org.automon.aspects;

import org.automon.implementations.NullImp;
import org.automon.implementations.OpenMon;

/**
 *
Aspect that advises the {@link org.aspectj.lang.annotation.Around} and {@link org.aspectj.lang.annotation.AfterThrowing} annotations.
 * The appropriate methods on {@link org.automon.implementations.OpenMon} methods are called. The advice typically times methods
 * and counts any exceptions  thrown however other behavior such as logging is also possible.

 *
 *
Note a developer should implement and provide any methods for this class or {@link org.automon.aspects.AspectJBase} or
 * {@link org.automon.aspects.SpringBase}.

 *
 *
Note: I used native aspect style instead of the @AspectJ style because around in @AspectJ style doesn't seem to allow for the
 * more performant use of the static part of the JoinPoint. The static part only seems to be available without first
 * creating the dynamic JoinPoint in native aspects. Native style aspects are more powerful and can later be extended by developers
 * with @AspectJ style, so it is probably the best option anyway.

 */
public abstract aspect AutomonAspect  {
    private OpenMon openMon = new NullImp();
    protected  boolean enable = true;

    public boolean isEnabled() {
        return enable;
    }

    public void enable(boolean shouldEnable) {
        enable = shouldEnable;
    }

    /**
     * monitor() advice - Wraps the given pointcut and calls the appropriate {@link org.automon.implementations.OpenMon} method at the beginning and end
     * of the method call.
     *
     * @return The advised methods value or void.
     * @throws Throwable If the method throws a {@link java.lang.Throwable} the advice will rethrow it.
     */
    Object around() throws Throwable : monitor()  {
        // Note: context is typically a Timer/Monitor object returned by the monitoring implementation (Jamon, JavaSimon, Metrics,...)
        // though to this advice it is simply an object and the advice doesn't care what the intent of the context/object is.
        Object context = openMon.start(thisJoinPointStaticPart);
        try {
            Object retVal = proceed();
            openMon.stop(context);
            return retVal;
        } catch (Throwable throwable) {
            openMon.stop(context, throwable);
            throw throwable;
        }
    }

    /**
     * exceptions() advice - Takes action on any Exception thrown.  It Tracks/Counts any exceptions thrown by the pointcut.
     */
    after() throwing(Throwable throwable): exceptions() {
        openMon.exception(thisJoinPoint, throwable);
    }

    /** Retreive monitoring implementation */
    public OpenMon getOpenMon() {
        return openMon;
    }

    /** Set monitoring implementation such as JAMon, Metrics, or JavaSimon */
    public void setOpenMon(OpenMon openMon) {
        this.openMon = openMon;
    }

    /** pointcut that determines what is monitored for performance/time */
    public pointcut monitor() : user_monitor() && sys_monitor();

    /** User should implement this pointcut to determine what should be monitored for performance/time */
    public abstract pointcut user_monitor();

    /** reserved pointcut for Automon team */
    public abstract pointcut sys_monitor();

    /** pointcut that determines what is monitored for exceptions.  It can be the same as the {@link #monitor()} poincut */
    public pointcut exceptions() : user_exceptions() && sys_exceptions();

    /** User should implement this pointcut to determine what should be monitored for performance/time */
    public abstract pointcut user_exceptions();

    /** reserved pointcut for Automon team */
    public abstract pointcut sys_exceptions();

}


hmmmm looks like trustin moved stack maintenance to the confguration/context object and i see why he did not call it a configuration now

git-svn-id: 90776817adfbd895fc5cfa90f675377e0a62e745@190952 13f79535-47bb-0310-9956-ffa450edef68

package org.apache.ldap.server.jndi;

import java.util.Map;
import java.util.Stack;
import java.util.Iterator;
import java.util.EmptyStackException;

import javax.naming.Name;
import javax.naming.Context;
import javax.naming.ldap.LdapContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.ModificationItem;

import org.apache.ldap.common.filter.ExprNode;
import org.apache.ldap.server.PartitionNexus;
import org.apache.ldap.server.db.Database;
import org.apache.ldap.server.ContextPartition;
import org.apache.ldap.server.invocation.Invocation;

/**
 * Aspect coupling the JNDI provider with the nexus thereby facilitating the
 * injection of interceptors between calls to the nexus from the JNDI.
 *
 * @author Alex Karasulu
 * @author $Author$
 * @version $Revision$
 */
public aspect ProviderNexusAspect
{
    // ------------------------------------------------------------------------
    // M E M B E R   I N T R O D U C T I O N S
    // ------------------------------------------------------------------------

    /**
     * Adds a static ThreadLocal for a Stack of LdapContexts representing nested
     * backend nexus calls made by the DefaultContextFactoryConfiguration's contexts within the same
     * thread of execution.
     */
    private static ThreadLocal DefaultContextFactoryConfiguration.s_contextStacks = new ThreadLocal();

    // ------------------------------------------------------------------------
    // M E T H O D   I N T R O D U C T I O N S
    // ------------------------------------------------------------------------

    /**
     * Pushes a calling LdapContext onto the Thread's ThreadLocal Stack before
     * calls are made on the nexus within the LdapContext code.
     *
     * @param context the caller or the current context for the nexus call
     */
    private static void DefaultContextFactoryConfiguration.push( LdapContext context )
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            stack = new Stack();
            s_contextStacks.set( stack );
        }

        stack.push( context );
    }

    /**
     * Pops the head of the Thread's ThreadLocal Stack after calls complete on
     * the nexus within the LdapContext code.
     *
     * @return the last LdapContext or caller
     */
    private static LdapContext DefaultContextFactoryConfiguration.pop()
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            throw new EmptyStackException();
        }

        return ( LdapContext ) stack.pop();
    }

    /**
     * Peeks at the head of the Thread's ThreadLocal Stack.
     *
     * @return the current LdapContext or caller
     */
    static LdapContext DefaultContextFactoryConfiguration.peek()
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            throw new EmptyStackException();
        }

        return ( LdapContext ) stack.peek();
    }

    // ------------------------------------------------------------------------
    // A S P E C T   M E T H O D S
    // ------------------------------------------------------------------------

    /**
     * Gets a shallow copy of the context stack.
     *
     * @return the context Stack.
     */
    private static Stack getContextStack()
    {
        Stack stack = ( Stack ) DefaultContextFactoryConfiguration.s_contextStacks.get();

        if ( stack == null )
        {
            return null;
        }

        return ( Stack ) stack.clone();
    }

    // ------------------------------------------------------------------------
    // P O I N T   C U T S
    // ------------------------------------------------------------------------

    /**
     * Selects join points on any public method calls made on the BackendNexus
     * interface implementing proxy from code executing within an LdapContext
     * caller.  Makes sure that Proxy methods (static) and the
     * getInvokationHandler() do not get selected.
     *
     * @param caller the calling LdapContext.
     */
    pointcut jndiNexusCalls( Context caller ):
        this( caller ) &&
        ! this( ContextPartition ) &&
        target( PartitionNexus ) &&
        ! target( Database ) &&
        (
        // these are for the ContextPartition interface methods

        // not used anymore since it was moved to RootNexus class
        // call( public Attributes getRootDSE() ) ||

        call( public Name getMatchedDn( Name, boolean ) ) ||
        call( public Name getSuffix( Name, boolean ) ) ||
		call( public Iterator listSuffixes( boolean ) ) ||
		call( public Attributes lookup( Name, String [] ) ) ||

		// these are for BackingStore interface methods
        call( public void add( String, Name, Attributes ) ) ||
        call( public void delete( Name ) ) ||
		call( public boolean hasEntry( Name ) ) ||
        call( public boolean isSuffix( Name ) ) ||
        call( public NamingEnumeration list( Name ) ) ||
		call( public Attributes lookup( Name ) ) ||
        call( public void modify( Name, int, Attributes ) ) ||
        call( public void modify( Name, ModificationItem [] ) ) ||
        call( public void modifyRn( Name, String, boolean ) ) ||
        call( public void move( Name, Name ) ) ||
        call( public void move( Name, Name, String, boolean ) ) ||
        call( public NamingEnumeration
           search( Name, Map, ExprNode, SearchControls ) ) );

    /**
     * Selects join points where the Invokation default constructor executes.
     *
     * @param invocation the Invocation instantiated
     */
    pointcut newInvocation( Invocation invocation ):
        target( invocation ) &&
        execution( Invocation.new(..) );

    // ------------------------------------------------------------------------
    // A D V I C E
    // ------------------------------------------------------------------------

    before( Context caller ):
        jndiNexusCalls( caller )
        {
    		DefaultContextFactoryConfiguration.push( ( LdapContext ) caller );
            //System.out.println( "\npushed " + caller + " for join point "
            //    + thisJoinPoint );
        }

    after( Context caller ):
        jndiNexusCalls( caller )
        {
            LdapContext head = DefaultContextFactoryConfiguration.pop();
            //System.out.println( "\npopped " + caller + " for join point "
            //    + thisJoinPoint );
        }

    after( Invocation invocation ):
        newInvocation( invocation )
        {
            invocation.setContextStack( getContextStack() );
            //System.out.println(
            //    "\nJust set the context stack on a new Invocation: "
            //    + thisJoinPoint );
        }
}

package org.apache.ldap.server.jndi;

import java.util.Map;
import java.util.Stack;
import java.util.Iterator;
import java.util.EmptyStackException;

import javax.naming.Name;
import javax.naming.Context;
import javax.naming.ldap.LdapContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.ModificationItem;

import org.apache.ldap.common.filter.ExprNode;
import org.apache.ldap.server.PartitionNexus;
import org.apache.ldap.server.db.Database;
import org.apache.ldap.server.ContextPartition;
import org.apache.ldap.server.invocation.Invocation;

/**
 * Aspect coupling the JNDI provider with the nexus thereby facilitating the
 * injection of interceptors between calls to the nexus from the JNDI.
 *
 * @author Alex Karasulu
 * @author $Author$
 * @version $Revision$
 */
public aspect ProviderNexusAspect
{
    // ------------------------------------------------------------------------
    // M E M B E R   I N T R O D U C T I O N S
    // ------------------------------------------------------------------------

    /**
     * Adds a static ThreadLocal for a Stack of LdapContexts representing nested
     * backend nexus calls made by the DefaultContextFactoryContext's contexts within the same
     * thread of execution.
     */
    private static ThreadLocal DefaultContextFactoryContext.s_contextStacks = new ThreadLocal();

    // ------------------------------------------------------------------------
    // M E T H O D   I N T R O D U C T I O N S
    // ------------------------------------------------------------------------

    /**
     * Pushes a calling LdapContext onto the Thread's ThreadLocal Stack before
     * calls are made on the nexus within the LdapContext code.
     *
     * @param context the caller or the current context for the nexus call
     */
    private static void DefaultContextFactoryContext.push( LdapContext context )
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            stack = new Stack();
            s_contextStacks.set( stack );
        }

        stack.push( context );
    }

    /**
     * Pops the head of the Thread's ThreadLocal Stack after calls complete on
     * the nexus within the LdapContext code.
     *
     * @return the last LdapContext or caller
     */
    private static LdapContext DefaultContextFactoryContext.pop()
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            throw new EmptyStackException();
        }

        return ( LdapContext ) stack.pop();
    }

    /**
     * Peeks at the head of the Thread's ThreadLocal Stack.
     *
     * @return the current LdapContext or caller
     */
    static LdapContext DefaultContextFactoryContext.peek()
    {
        Stack stack = ( Stack ) s_contextStacks.get();

        if ( null == stack )
        {
            throw new EmptyStackException();
        }

        return ( LdapContext ) stack.peek();
    }

    // ------------------------------------------------------------------------
    // A S P E C T   M E T H O D S
    // ------------------------------------------------------------------------

    /**
     * Gets a shallow copy of the context stack.
     *
     * @return the context Stack.
     */
    private static Stack getContextStack()
    {
        Stack stack = ( Stack ) DefaultContextFactoryContext.s_contextStacks.get();

        if ( stack == null )
        {
            return null;
        }

        return ( Stack ) stack.clone();
    }

    // ------------------------------------------------------------------------
    // P O I N T   C U T S
    // ------------------------------------------------------------------------

    /**
     * Selects join points on any public method calls made on the BackendNexus
     * interface implementing proxy from code executing within an LdapContext
     * caller.  Makes sure that Proxy methods (static) and the
     * getInvokationHandler() do not get selected.
     *
     * @param caller the calling LdapContext.
     */
    pointcut jndiNexusCalls( Context caller ):
        this( caller ) &&
        ! this( ContextPartition ) &&
        target( PartitionNexus ) &&
        ! target( Database ) &&
        (
        // these are for the ContextPartition interface methods

        // not used anymore since it was moved to RootNexus class
        // call( public Attributes getRootDSE() ) ||

        call( public Name getMatchedDn( Name, boolean ) ) ||
        call( public Name getSuffix( Name, boolean ) ) ||
		call( public Iterator listSuffixes( boolean ) ) ||
		call( public Attributes lookup( Name, String [] ) ) ||

		// these are for BackingStore interface methods
        call( public void add( String, Name, Attributes ) ) ||
        call( public void delete( Name ) ) ||
		call( public boolean hasEntry( Name ) ) ||
        call( public boolean isSuffix( Name ) ) ||
        call( public NamingEnumeration list( Name ) ) ||
		call( public Attributes lookup( Name ) ) ||
        call( public void modify( Name, int, Attributes ) ) ||
        call( public void modify( Name, ModificationItem [] ) ) ||
        call( public void modifyRn( Name, String, boolean ) ) ||
        call( public void move( Name, Name ) ) ||
        call( public void move( Name, Name, String, boolean ) ) ||
        call( public NamingEnumeration
           search( Name, Map, ExprNode, SearchControls ) ) );

    /**
     * Selects join points where the Invokation default constructor executes.
     *
     * @param invocation the Invocation instantiated
     */
    pointcut newInvocation( Invocation invocation ):
        target( invocation ) &&
        execution( Invocation.new(..) );

    // ------------------------------------------------------------------------
    // A D V I C E
    // ------------------------------------------------------------------------

    before( Context caller ):
        jndiNexusCalls( caller )
        {
    		DefaultContextFactoryContext.push( ( LdapContext ) caller );
            //System.out.println( "\npushed " + caller + " for join point "
            //    + thisJoinPoint );
        }

    after( Context caller ):
        jndiNexusCalls( caller )
        {
            LdapContext head = DefaultContextFactoryContext.pop();
            //System.out.println( "\npopped " + caller + " for join point "
            //    + thisJoinPoint );
        }

    after( Invocation invocation ):
        newInvocation( invocation )
        {
            invocation.setContextStack( getContextStack() );
            //System.out.println(
            //    "\nJust set the context stack on a new Invocation: "
            //    + thisJoinPoint );
        }
}


comments for PdfExport

comments for PdfExport

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import model.db.DataObject;
import model.db.GameData;
import view.GUI;
import view.SchafkopfTableModel;

public privileged aspect PdfExport {

    /** This precendence makes the order of the items in the file menu sure */
    declare precedence : Import, HtmlExport, PdfExport;
    private GUI gui;

    /**
     * catch constructor call, so that we have the correct gui, to refer to everywhere
     */
    after() returning(GUI gui): call(GUI.new(*)) {
        this.gui = gui;
    }

    private String[][] SchafkopfTableModel.asTextArray() {
        String[][] completeTable = data.asTextArray();

        String[] headerLine = new String[getColumnCount()];
        for (int i = 0; i < getColumnCount(); i++) {
            headerLine[i] = getColumnName(i);
        }
        completeTable[0] = headerLine;
        return completeTable;
    }

    private String[][] GameData.asTextArray() {
        Iterator<DataObject> it = data.iterator();
        String[][] rows = new String[data.size()+1][];
        int index = 1;
        while (it.hasNext()) {
            rows[index] = it.next().asTextArray(index-1);
            index++;
        }
        return rows;
    }

    /**
     * Add pdf report feature to menu bar
     */
    after() returning(JMenuBar bar): call(JMenuBar GUI.createMenu()) {
        JMenuItem itemExportPdf = new JMenuItem("Generiere PDF Report");
        itemExportPdf.addActionListener(new PDFReportListener());

        Component[] menus = bar.getComponents();
        if (menus.length != 0 && menus[0] instanceof JMenu) {
            ((JMenu)bar.getComponents()[0]).add(itemExportPdf, 0);
        } else {
            throw new AssertionError("There should be a menu entry!");
        }
    }

    /**
     * generate pdf report (execution of PDFReportListener is suppressed, this
     * is just an empty method, to be able to create this pointcut
     */
    void around(PDDocument document) throws IOException
          : execution (* PDFReportListener.drawTable(PDDocument))
          && args(document) {
        PDPage page = new PDPage();
        document.addPage(page);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        float y =750f;
        float margin =60f;
        String[][] content = ((SchafkopfTableModel) gui.table.getModel()).asTextArray();

        final int rows = content.length;
        final int cols = content[0].length;
        final float rowHeight = 20f;
        final float tableWidth = page.findMediaBox().getWidth()-(2*margin);
        final float tableHeight = rowHeight * rows;
        final float colWidth = tableWidth/(float)cols;
        final float cellMargin=5f;

        // TODO multisite tables
        //draw the rows
        float nexty = y ;
        for (int i = 0; i <= rows; i++) {
            contentStream.drawLine(margin,nexty,margin+tableWidth,nexty);
            nexty-= rowHeight;
        }

        //draw the columns
        float nextx = margin;
        for (int i = 0; i <= cols; i++) {
            contentStream.drawLine(nextx,y,nextx,y-tableHeight);
            nextx += colWidth;
        }

        //now add the text
        contentStream.setFont(PDType1Font.HELVETICA_BOLD,10);

        float textx = margin+cellMargin;
        float texty = y-15;
        for(int i = 0; i < content.length; i++){
            for(int j = 0 ; j < content[i].length; j++){
                String text = content[i][j];
                contentStream.beginText();
                contentStream.moveTextPositionByAmount(textx,texty);
                contentStream.drawString(text);
                contentStream.endText();
                textx += colWidth;
            }
            texty-=rowHeight;
            textx = margin+cellMargin;
        }
        contentStream.close();
    }
}

class PDFReportListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Create a document and add a page to it
        PDDocument document = new PDDocument();

        try {
            drawTable(document);

            // Save the results and ensure that the document is properly closed:
            document.save("Session_vom_"+new SimpleDateFormat("dd.MM_'um'_HH:mm").format(Calendar.getInstance().getTime()) + ".pdf");
        } catch (IOException | COSVisitorException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                document.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /** filled with pointcut from pdfExport.aj*/
    public static void drawTable(PDDocument document) throws IOException {
    }
}

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import model.db.DataObject;
import model.db.GameData;
import view.GUI;
import view.SchafkopfTableModel;

public privileged aspect PdfExport {

    declare precedence : Import, HtmlExport, PdfExport;
    private GUI gui;

    /**
     * catch constructor call, so that we have the correct gui, to refer to everywhere
     */
    after() returning(GUI gui): call(GUI.new(*)) {
        this.gui = gui;
    }

    private String[][] SchafkopfTableModel.asTextArray() {
        String[][] completeTable = data.asTextArray();

        String[] headerLine = new String[getColumnCount()];
        for (int i = 0; i < getColumnCount(); i++) {
            headerLine[i] = getColumnName(i);
        }
        completeTable[0] = headerLine;
        return completeTable;
    }

    private String[][] GameData.asTextArray() {
        Iterator<DataObject> it = data.iterator();
        String[][] rows = new String[data.size()+1][];
        int index = 1;
        while (it.hasNext()) {
            rows[index] = it.next().asTextArray(index-1);
            index++;
        }
        return rows;
    }

    /**
     * Add pdf report feature to menu bar
     */
    after() returning(JMenuBar bar): call(JMenuBar GUI.createMenu()) {
        JMenuItem itemExportPdf = new JMenuItem("Generiere PDF Report");
        itemExportPdf.addActionListener(new PDFReportListener());

        Component[] menus = bar.getComponents();
        if (menus.length != 0 && menus[0] instanceof JMenu) {
            ((JMenu)bar.getComponents()[0]).add(itemExportPdf, 0);
        } else {
            throw new AssertionError("There should be a menu entry!");
        }
    }

    /**
     * generate pdf report (execution of PDFReportListener is suppressed, this
     * is just an empty method, to be able to create this pointcut
     */
    void around(PDDocument document) throws IOException
          : execution (* PDFReportListener.drawTable(PDDocument))
          && args(document) {
        PDPage page = new PDPage();
        document.addPage(page);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        float y =750f;
        float margin =60f;
        String[][] content = ((SchafkopfTableModel) gui.table.getModel()).asTextArray();

        final int rows = content.length;
        final int cols = content[0].length;
        final float rowHeight = 20f;
        final float tableWidth = page.findMediaBox().getWidth()-(2*margin);
        final float tableHeight = rowHeight * rows;
        final float colWidth = tableWidth/(float)cols;
        final float cellMargin=5f;

        // TODO multisite tables
        //draw the rows
        float nexty = y ;
        for (int i = 0; i <= rows; i++) {
            contentStream.drawLine(margin,nexty,margin+tableWidth,nexty);
            nexty-= rowHeight;
        }

        //draw the columns
        float nextx = margin;
        for (int i = 0; i <= cols; i++) {
            contentStream.drawLine(nextx,y,nextx,y-tableHeight);
            nextx += colWidth;
        }

        //now add the text
        contentStream.setFont(PDType1Font.HELVETICA_BOLD,10);

        float textx = margin+cellMargin;
        float texty = y-15;
        for(int i = 0; i < content.length; i++){
            for(int j = 0 ; j < content[i].length; j++){
                String text = content[i][j];
                contentStream.beginText();
                contentStream.moveTextPositionByAmount(textx,texty);
                contentStream.drawString(text);
                contentStream.endText();
                textx += colWidth;
            }
            texty-=rowHeight;
            textx = margin+cellMargin;
        }
        contentStream.close();
    }
}

class PDFReportListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Create a document and add a page to it
        PDDocument document = new PDDocument();

        try {
            drawTable(document);

            // Save the results and ensure that the document is properly closed:
            document.save("Session_vom_"+new SimpleDateFormat("dd.MM_'um'_HH:mm").format(Calendar.getInstance().getTime()) + ".pdf");
        } catch (IOException | COSVisitorException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                document.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /** filled with pointcut from pdfExport.aj*/
    public static void drawTable(PDDocument document) throws IOException {
    }
}


addressing some pr comments

addressing some pr comments

/*
 * 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.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> noActorClazz = Option.empty();
    private final ConcurrentHashMap<Option<String>, AtomicLong> samplingCounters;
    private final ConcurrentHashMap<Option<String>, AtomicLong> numberOfActors;

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

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

    // decide whether to include this ActorCell in our measurements
    private boolean includeActorPath(final PathAndClass pathAndClass) {
        if (!this.agentConfiguration.incuded().accept(pathAndClass)) return false;
        if (this.agentConfiguration.excluded().accept(pathAndClass)) return false;

        if (this.agentConfiguration.includeSystemAgents()) return true;

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

    // get the sample rate for an actor
    private int getSampleRate(final PathAndClass pathAndClass) {
        return this.agentConfiguration.sampling().getRate(pathAndClass);
    }

    // decide whether to sample an actor on a particular occasion
    private final boolean sampleMessage(final PathAndClass pathAndClass) {
        int sampleRate = getSampleRate(pathAndClass);
        if (sampleRate == 1) return true;

        this.samplingCounters.putIfAbsent(pathAndClass.actorClassName(), new AtomicLong(0));
        long timesSeenSoFar = this.samplingCounters.get(pathAndClass.actorClassName()).incrementAndGet();
        return (timesSeenSoFar % sampleRate == 1); // == 1 to log first value (incrementAndGet returns updated value)
    }

    // get the tags for the cell
    private String[] getTags(final ActorPath actorPath, final Actor actor) {
        List<String> tags = new ArrayList<String>();

        // TODO: Improve detection of routed actors. This relies only on the naming :(.
        String lastPathElement = actorPath.elements().last();
        if (lastPathElement.startsWith("$")) {
            // this is routed actor.
            tags.add(actorPath.parent().toString());
            if (this.agentConfiguration.includeRoutees()) tags.add(actorPath.toString());
        } else {
            // there is no supervisor
            tags.add(actorPath.toString());
        }
        if (actor != null) {
            tags.add(String.format("akka:%s.%s", actor.context().system().name(), actor.getClass().getCanonicalName()));
        }

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

    // returns the canonical name of the actor type associated with an ActorCell
    private String uncheckedActorNameFrom(final ActorCell actorCell) {
        return uncheckedActorNameFrom(actorCell.props());
    }

    // returns the canonical name of the actor type associated with a Props instance
    private String uncheckedActorNameFrom(final Props props) {
        return props.actorClass().getCanonicalName();
    }

    /**
     * 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, Option.apply(uncheckedActorNameFrom(actorCell)));
        if (!includeActorPath(pathAndClass) || !sampleMessage(pathAndClass)) return proceed(actorCell, msg);

        int samplingRate = getSampleRate(pathAndClass);

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

        // record the queue size
        this.counterInterface.recordGaugeValue("akka.queue.size", actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter("akka.actor.delivered", samplingRate, tags);
        this.counterInterface.incrementCounter("akka.actor.delivered." + msg.getClass().getSimpleName(), 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("akka.actor.duration", (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(), actorCell.actor());
        this.counterInterface.incrementCounter("akka.actor.error", tags);
        this.counterInterface.incrementCounter(String.format("akka.actor.error.%s", failure.getMessage()), 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(), null);
            this.counterInterface.incrementCounter("akka.actor.undelivered", tags);
            this.counterInterface.incrementCounter("akka.actor.undelivered." + unhandledMessage.getMessage().getClass().getSimpleName(), tags);
        }
    }

    /**
     * Advises the {@code actorOf} method of {@code ActorCell} and {@code ActorSystem}
     *
     * @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) {
        recordActorCreation(props, actor);
    }
    /**
     * Advises the {@code actorOf} method of {@code ActorCell} and {@code ActorSystem} when actor is named in construction
     *
     * @param props the {@code Props} instance used in the call
     * @param actorName the {@code String} used to name the actor at creation site
     * @param actor the {@code ActorRef} returned from the call
     */
    after(Props props, String actorName) returning (ActorRef actor): Pointcuts.namedActorOf(props, actorName) {
        recordActorCreation(props, actor);
    }

    // method containing the recording logic for advising actor creation
    private void recordActorCreation(Props props, ActorRef actor) {
        if (!includeActorPath(new PathAndClass(actor.path(), this.noActorClazz))) return;
        final String uncheckedClassName = uncheckedActorNameFrom(props);
        final Option<String> className = Option.apply(uncheckedClassName);

        this.numberOfActors.putIfAbsent(className, new AtomicLong(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 long value = this.numberOfActors.get(className).incrementAndGet();

        // record the current number of actors of this type
        this.counterInterface.recordGaugeValue("akka.actor.count", (int)value, uncheckedClassName);
    }

    /**
     * Advises the {@code LocalActorRef.stop} method
     *
     *
     * @param actorCell the {@code ActorCell} of the actor being stopped
     */
    after(ActorCell actorCell) : Pointcuts.actorCellInternalStop(actorCell) {
        if (!includeActorPath(new PathAndClass(actorCell.self().path(), this.noActorClazz))) return;
        final String uncheckedClassName = uncheckedActorNameFrom(actorCell);
        final Option<String> className = Option.apply(uncheckedClassName);

        this.numberOfActors.putIfAbsent(className, new AtomicLong(0));
        final long value = this.numberOfActors.get(className).decrementAndGet();

        this.counterInterface.recordGaugeValue("akka.actor.count", (int)value, uncheckedClassName);
    }

}

/*
 * 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.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> noActorClazz = Option.empty();
    private final ConcurrentHashMap<Option<String>, AtomicLong> samplingCounters;
    private final ConcurrentHashMap<Option<String>, AtomicLong> numberOfActors;

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

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

    // decide whether to include this ActorCell in our measurements
    private boolean includeActorPath(final PathAndClass pathAndClass) {
        if (!this.agentConfiguration.incuded().accept(pathAndClass)) return false;
        if (this.agentConfiguration.excluded().accept(pathAndClass)) return false;

        if (this.agentConfiguration.includeSystemAgents()) return true;

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

    // get the sample rate for an actor
    private int getSampleRate(final PathAndClass pathAndClass) {
        return this.agentConfiguration.sampling().getRate(pathAndClass);
    }

    // decide whether to sample an actor on a particular occasion
    private final boolean sampleMessage(final PathAndClass pathAndClass) {
        int sampleRate = getSampleRate(pathAndClass);
        if (sampleRate == 1) return true;

        this.samplingCounters.putIfAbsent(pathAndClass.actorClassName(), new AtomicLong(0));
        long timesSeenSoFar = this.samplingCounters.get(pathAndClass.actorClassName()).incrementAndGet();
        return (timesSeenSoFar % sampleRate == 1); // == 1 to log first value (incrementAndGet returns updated value)
    }

    // get the tags for the cell
    private String[] getTags(final ActorPath actorPath, final Actor actor) {
        List<String> tags = new ArrayList<String>();

        // TODO: Improve detection of routed actors. This relies only on the naming :(.
        String lastPathElement = actorPath.elements().last();
        if (lastPathElement.startsWith("$")) {
            // this is routed actor.
            tags.add(actorPath.parent().toString());
            if (this.agentConfiguration.includeRoutees()) tags.add(actorPath.toString());
        } else {
            // there is no supervisor
            tags.add(actorPath.toString());
        }
        if (actor != null) {
            tags.add(String.format("akka:%s.%s", actor.context().system().name(), actor.getClass().getCanonicalName()));
        }

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

    private String uncheckedActorNameFrom(final ActorCell actorCell) {
        return uncheckedActorNameFrom(actorCell.props());
    }
    private String uncheckedActorNameFrom(final Props props) {
        return props.actorClass().getCanonicalName();
    }

    /**
     * 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, Option.apply(uncheckedActorNameFrom(actorCell)));
        if (!includeActorPath(pathAndClass) || !sampleMessage(pathAndClass)) return proceed(actorCell, msg);

        int samplingRate = getSampleRate(pathAndClass);

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

        // record the queue size
        this.counterInterface.recordGaugeValue("akka.queue.size", actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter("akka.actor.delivered", samplingRate, tags);
        this.counterInterface.incrementCounter("akka.actor.delivered." + msg.getClass().getSimpleName(), 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("akka.actor.duration", (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(), actorCell.actor());
        this.counterInterface.incrementCounter("akka.actor.error", tags);
        this.counterInterface.incrementCounter(String.format("akka.actor.error.%s", failure.getMessage()), 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(), null);
            this.counterInterface.incrementCounter("akka.actor.undelivered", tags);
            this.counterInterface.incrementCounter("akka.actor.undelivered." + unhandledMessage.getMessage().getClass().getSimpleName(), tags);
        }
    }

    /**
     * Advises the {@code actorOf} method of {@code ActorCell} and {@code ActorSystem}
     *
     * @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) {
        recordActorCreation(props, actor);
    }
    /**
     * Advises the {@code actorOf} method of {@code ActorCell} and {@code ActorSystem} when actor is named in construction
     *
     * @param props the {@code Props} instance used in the call
     * @param actorName the {@code String} used to name the actor at creation site
     * @param actor the {@code ActorRef} returned from the call
     */
    after(Props props, String actorName) returning (ActorRef actor): Pointcuts.namedActorOf(props, actorName) {
        recordActorCreation(props, actor);
    }

    // method containing the recording logic for advising actor creation
    void recordActorCreation(Props props, ActorRef actor) {
        if (!includeActorPath(new PathAndClass(actor.path(), this.noActorClazz))) return;
        final String uncheckedClassName = uncheckedActorNameFrom(props);
        final Option<String> className = Option.apply(uncheckedClassName);

        this.numberOfActors.putIfAbsent(className, new AtomicLong(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 long value = this.numberOfActors.get(className).incrementAndGet();

        // record the current number of actors of this type
        this.counterInterface.recordGaugeValue("akka.actor.count", (int)value, uncheckedClassName);
    }

    /**
     * Advises the {@code LocalActorRef.stop} method
     *
     *
     * @param actorCell the {@code ActorCell} of the actor being stopped
     */
    after(ActorCell actorCell) : Pointcuts.actorCellInternalStop(actorCell) {
        if (!includeActorPath(new PathAndClass(actorCell.self().path(), this.noActorClazz))) return;
        final String uncheckedClassName = uncheckedActorNameFrom(actorCell);
        final Option<String> className = Option.apply(uncheckedClassName);

        this.numberOfActors.putIfAbsent(className, new AtomicLong(0));
        final long value = this.numberOfActors.get(className).decrementAndGet();

        this.counterInterface.recordGaugeValue("akka.actor.count", (int)value, uncheckedClassName);
    }

}


Fixed #2553.

Fixed #2553.

git-svn-id: f4ecfe233223879a4a16cd7937f11b5152963d8e@19496 5e8d7ff9-d8ef-0310-90f0-a4852d11357a

/*
 * Copyright 2005-2009 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import java.util.Locale;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;

@SuppressWarnings("restriction")
public privileged aspect DOMAspect {
  pointcut internalCreateAST(ASTParser parser, IProgressMonitor monitor) :
    execution(ASTNode ASTParser.internalCreateAST(IProgressMonitor)) &&
    args(monitor) &&
    target(parser);

  ASTNode around(ASTParser parser, IProgressMonitor monitor) :
    internalCreateAST(parser, monitor) {
    try {
      if (!(parser.typeRoot instanceof IScalaCompilationUnit))
        return proceed(parser, monitor);

      ICompilationUnit cu = (ICompilationUnit)parser.typeRoot;
      org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit)cu;

      IType[] topLevelTypes = cu.getTypes();
      int length = topLevelTypes.length;
      if (length == 0)
        throw new IllegalStateException();

      SourceTypeElementInfo[] topLevelInfos = new SourceTypeElementInfo[length];
      for (int i = 0; i < length; i++) {
        topLevelInfos[i] = (SourceTypeElementInfo) ((SourceType)topLevelTypes[i]).getElementInfo();
      }
      char[] fileName = ((ISourceType)topLevelInfos[0]).getFileName();

      CompilationResult result = new CompilationResult(fileName, 1, 1, 100);

      JavaProject javaProject = (JavaProject)cu.getJavaProject();
      Map compilerOptions0 = javaProject.getOptions(true);
      CompilerOptions compilerOptions = new CompilerOptions(compilerOptions0);
      compilerOptions.storeAnnotations = true;

      ProblemReporter problemReporter =
        new ProblemReporter(
          DefaultErrorHandlingPolicies.proceedWithAllProblems(),
          compilerOptions,
          new DefaultProblemFactory(Locale.getDefault()));

      int flags = SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE;

      CompilationUnitDeclaration unit =
        SourceTypeConverter.buildCompilationUnit(topLevelInfos, flags, problemReporter, result);

      INameEnvironment ne = javaProject.newSearchableNameEnvironment(DefaultWorkingCopyOwner.PRIMARY);
      final LookupEnvironment le = new LookupEnvironment(null, compilerOptions, problemReporter, ne);
      ITypeRequestor typeRequestor = new ITypeRequestor() {
        public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
          le.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
        }
        public void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit, AccessRestriction accessRestriction) {}
        public void accept(ISourceType[] sourceType, PackageBinding packageBinding, AccessRestriction accessRestriction) {}
      };
      le.typeRequestor = typeRequestor;

      le.buildTypeBindings(unit, null);
      le.completeTypeBindings();
      fixTypes(unit.types);

      AST ast = AST.newAST(AST.JLS3);
      ast.setFlag(AST.RESOLVED_BINDINGS);
      ast.setDefaultNodeFlag(ASTNode.ORIGINAL);

      org.eclipse.jdt.core.dom.ASTConverter converter =
        new org.eclipse.jdt.core.dom.ASTConverter(compilerOptions0, true, monitor);

      org.eclipse.jdt.core.dom.BindingResolver resolver =
        new org.eclipse.jdt.core.dom.DefaultBindingResolver(
          unit.scope,
          DefaultWorkingCopyOwner.PRIMARY,
          new org.eclipse.jdt.core.dom.DefaultBindingResolver.BindingTables(),
          true);
      ast.setBindingResolver(resolver);
      converter.setAST(ast);

      ASTNode node = converter.convert(unit, sourceUnit.getContents());
      return node;
    } catch (JavaModelException ex) {
      throw new IllegalArgumentException(ex);
    }
  }

  private void fixTypes(TypeDeclaration[] types) {
    for(int i = 0, iLimit = types.length; i < iLimit ; ++i) {
      TypeDeclaration tpe = types[i];
      tpe.binding.getAnnotationTagBits();
      tpe.scope.buildFields();
      tpe.scope.buildMethods();
      fixFields(tpe.fields);
      fixMethods(tpe.methods);
      fixTypes(tpe.memberTypes);
    }
  }

  private void fixMethods(AbstractMethodDeclaration[] methods) {
    if (methods == null)
      return;

    for(int i = 0, iLimit = methods.length; i < iLimit; ++i) {
      AbstractMethodDeclaration m = methods[i];
      m.bodyStart = m.declarationSourceStart;
      m.bodyEnd = m.declarationSourceEnd;
      m.binding.getAnnotationTagBits();
    }
  }

  private void fixFields(AbstractVariableDeclaration[] fields) {
    if (fields == null)
      return;

    for(int i = 0, iLimit = fields.length; i < iLimit; ++i) {
      AbstractVariableDeclaration f = fields[i];
      f.declarationEnd = f.declarationSourceEnd;
    }
  }
}

/*
 * Copyright 2005-2009 LAMP/EPFL
 */
// $Id$

package scala.tools.eclipse.contribution.weaving.jdt.core;

import java.util.Locale;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;

import scala.tools.eclipse.contribution.weaving.jdt.IScalaCompilationUnit;

@SuppressWarnings("restriction")
public privileged aspect DOMAspect {
  pointcut internalCreateAST(ASTParser parser, IProgressMonitor monitor) :
    execution(ASTNode ASTParser.internalCreateAST(IProgressMonitor)) &&
    args(monitor) &&
    target(parser);

  ASTNode around(ASTParser parser, IProgressMonitor monitor) :
    internalCreateAST(parser, monitor) {
    try {
      if (!(parser.typeRoot instanceof IScalaCompilationUnit))
        return proceed(parser, monitor);

      ICompilationUnit cu = (ICompilationUnit)parser.typeRoot;
      org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit)cu;

      IType[] topLevelTypes = cu.getTypes();
      int length = topLevelTypes.length;
      if (length == 0)
        throw new IllegalStateException();

      SourceTypeElementInfo[] topLevelInfos = new SourceTypeElementInfo[length];
      for (int i = 0; i < length; i++) {
        topLevelInfos[i] = (SourceTypeElementInfo) ((SourceType)topLevelTypes[i]).getElementInfo();
      }
      char[] fileName = ((ISourceType)topLevelInfos[0]).getFileName();

      CompilationResult result = new CompilationResult(fileName, 1, 1, 100);

      JavaProject javaProject = (JavaProject)cu.getJavaProject();
      Map compilerOptions0 = javaProject.getOptions(true);
      CompilerOptions compilerOptions = new CompilerOptions(compilerOptions0);
      compilerOptions.storeAnnotations = true;

      ProblemReporter problemReporter =
        new ProblemReporter(
          DefaultErrorHandlingPolicies.proceedWithAllProblems(),
          compilerOptions,
          new DefaultProblemFactory(Locale.getDefault()));

      int flags = SourceTypeConverter.FIELD_AND_METHOD | SourceTypeConverter.MEMBER_TYPE;

      CompilationUnitDeclaration unit =
        SourceTypeConverter.buildCompilationUnit(topLevelInfos, flags, problemReporter, result);

      INameEnvironment ne = javaProject.newSearchableNameEnvironment(DefaultWorkingCopyOwner.PRIMARY);
      final LookupEnvironment le = new LookupEnvironment(null, compilerOptions, problemReporter, ne);
      ITypeRequestor typeRequestor = new ITypeRequestor() {
        public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
          le.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
        }
        public void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit, AccessRestriction accessRestriction) {}
        public void accept(ISourceType[] sourceType, PackageBinding packageBinding, AccessRestriction accessRestriction) {}
      };
      le.typeRequestor = typeRequestor;

      le.buildTypeBindings(unit, null);
      le.completeTypeBindings();
      fixTypes(unit.types);

      AST ast = AST.newAST(AST.JLS3);
      ast.setFlag(AST.RESOLVED_BINDINGS);
      ast.setDefaultNodeFlag(ASTNode.ORIGINAL);

      org.eclipse.jdt.core.dom.ASTConverter converter =
        new org.eclipse.jdt.core.dom.ASTConverter(compilerOptions0, true, monitor);

      org.eclipse.jdt.core.dom.BindingResolver resolver =
        new org.eclipse.jdt.core.dom.DefaultBindingResolver(
          unit.scope,
          DefaultWorkingCopyOwner.PRIMARY,
          new org.eclipse.jdt.core.dom.DefaultBindingResolver.BindingTables(),
          true);
      ast.setBindingResolver(resolver);
      converter.setAST(ast);

      ASTNode node = converter.convert(unit, sourceUnit.getContents());
      return node;
    } catch (JavaModelException ex) {
      throw new IllegalArgumentException(ex);
    }
  }

  private void fixTypes(TypeDeclaration[] types) {
    for(int i = 0, iLimit = types.length; i < iLimit ; ++i) {
      TypeDeclaration tpe = types[i];
      tpe.binding.getAnnotationTagBits();
      tpe.scope.buildFields();
      tpe.scope.buildMethods();
      fixMethods(tpe, tpe.methods);
      fixTypes(tpe.memberTypes);
    }
  }

  private void fixMethods(TypeDeclaration tpe, AbstractMethodDeclaration[] methods) {
    for(int i = 0, iLimit = methods.length; i < iLimit; ++i) {
      AbstractMethodDeclaration m = methods[i];
      m.bodyStart = m.declarationSourceStart;
      m.bodyEnd = m.declarationSourceEnd;
      m.binding.getAnnotationTagBits();
    }
  }
}


Fixed format and javadoc

Fixed format and javadoc

import java.io.IOException;

import model.SystemValues.Games;
import model.SystemValues.Players;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import view.GUI;

public privileged aspect StatisticsExport {

	declare precedence: StatisticsExport, GraphExport, PdfExport;
	private GUI gui;

	/**
	 * catch constructor call, so that we have the correct gui, to refer to
	 * everywhere
	 */
	after() returning(GUI gui): call(GUI.new(*)) {
		this.gui = gui;
	}

	/**
	 * Catch the call on {@link PDFReportListener.drawTable(PDDocument)} to get
	 * the pdf creator object.
	 *
	 * This method then creates the pages and writes the statistics to the pdf.
	 *
	 * @param document
	 * @throws IOException
	 */
	after(PDDocument document) returning() throws IOException
    		: call(* PDFReportListener.drawTable(PDDocument))
    		&& args(document) {
		// write overall statistics to pdf
		PDPage page = new PDPage();
		document.addPage(page);
		PDPageContentStream contentStream = new PDPageContentStream(document,
				page);

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 15);
		contentStream.moveTextPositionByAmount(100, 680);
		contentStream.drawString("Statistik ueber das gesamte Spiel");
		contentStream.endText();

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
		createOverallContent(contentStream);
		contentStream.endText();
		contentStream.close();

		// write individual statistics to pdf
		page = new PDPage();
		document.addPage(page);
		contentStream = new PDPageContentStream(document, page);

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 15);
		contentStream.moveTextPositionByAmount(100, 680);
		contentStream.drawString("Statistik fuer jeden einzelnen Spieler");
		contentStream.endText();

		for (int i = 0; i < Players.values().length; ++i) {
			contentStream.beginText();
			contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
			createIndividualContent(contentStream, Players.values()[i]);
			contentStream.endText();
			contentStream.close();
			if (i < Players.values().length - 1) {
				page = new PDPage();
				document.addPage(page);
				contentStream = new PDPageContentStream(document, page);
			}
		}
	}

	/**
	 * Write statistics to given contentStream of a pdf page. These
	 * are the overall statistics.
	 *
	 * @param contentStream
	 *            The contentStream of the pdf page to write on.
	 * @throws IOException
	 */
	private void createOverallContent(PDPageContentStream contentStream)
			throws IOException {
		OverallStatistics data = gui.model.gameDB.getOverallStatistics();

		contentStream.moveTextPositionByAmount(50, 650);
		contentStream.drawString("#Spiele (ohne weiter): "
				+ data.getAnzahlSpieleGesamt() + " (gewonnen: "
				+ String.format("%.2f", data.getGesamtWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("#Rufspiele: " + data.getAnzahlRufspiele()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getRufspieleWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Rufspiel: "
				+ data.getTeuerstesRufspiel());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Soli gesamt: " + data.getAnzahlSoliGesamt()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliGesamtWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("#Soli normal: " + data.getAnzahlSoli()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliNormalWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo: "
				+ data.getTeuerstesSolo());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Solo Tout: " + data.getAnzahlSoliTout()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliToutWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo Tout: "
				+ data.getTeuerstesSoloTout());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Solo Sie: " + data.getAnzahlSoliSie());

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo Sie: "
				+ data.getTeuerstesSoloSie());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Weiter: " + data.getAnzahlWeiter());
	}

	/**
	 * Write the individual statistics for a given player to the
	 * given contentStream.
	 *
	 * @param contentStream
	 * @param player
	 * @throws IOException
	 */
	private void createIndividualContent(PDPageContentStream contentStream,
			Players player) throws IOException {
		contentStream.moveTextPositionByAmount(50, 650);
		contentStream.drawString(player.toString());

		contentStream.moveTextPositionByAmount(0, -22);

		PlayerWiseStatistics data = gui.model.getGameData()
				.getPlayerWiseStatistics(player);

		contentStream.drawString("Gespielte Spiele:");
		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("- Gesamt: " + data.getGamesPlayedTot()
				+ ", davon gewonnen: " + data.getGamesWonTot() + " ("
				+ String.format("%.2f", data.getGamesWonPerc()) + "%)");

		for (Games game : Games.values()) {
			if (game != Games.WEITER && game != Games.NONE) {
				int i = game.ordinal();
				contentStream.moveTextPositionByAmount(0, -16);
				contentStream.drawString("- "
						+ game.toString()
						+ ": "
						+ data.getGamesPlayedPerType()[i]
						+ ", davon gewonnen: "
						+ data.getGamesWonPerType()[i]
						+ " ("
						+ String.format("%.2f",
								data.getGamesWonPerTypePerc()[i]) + "%");
			}
		}

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream
				.drawString("Höchster Kontostand: " + data.getHighestAcc());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Niedrigster Kontostand: "
				+ data.getLowestAcc());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Größter Gewinn: " + data.getHighestWin());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Größter Verlust: " + data.getHighestLoss());

		contentStream.moveTextPositionByAmount(0, -32);
	}

}

import java.io.IOException;

import model.SystemValues.Games;
import model.SystemValues.Players;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

import view.GUI;

public privileged aspect StatisticsExport {

	declare precedence: StatisticsExport, GraphExport, PdfExport;
	private GUI gui;

	/**
	 * catch constructor call, so that we have the correct gui, to refer to
	 * everywhere
	 */
	after() returning(GUI gui): call(GUI.new(*)) {
		this.gui = gui;
	}

	/**
	 * Catch the call on {@link PDFReportListener.drawTable(PDDocument)} to get
	 * the pdf creator object.
	 *
	 * @param document
	 * @throws IOException
	 */
	after(PDDocument document) returning() throws IOException
    : call(* PDFReportListener.drawTable(PDDocument))
    && args(document) {
		PDPage page = new PDPage();
		document.addPage(page);
		PDPageContentStream contentStream = new PDPageContentStream(document,
				page);

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 15);
		contentStream.moveTextPositionByAmount(100, 680);
		contentStream.drawString("Statistik ueber das gesamte Spiel");
		contentStream.endText();

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
		createOverallContent(contentStream);
		contentStream.endText();
		contentStream.close();

		page = new PDPage();
		document.addPage(page);
		contentStream = new PDPageContentStream(document, page);

		contentStream.beginText();
		contentStream.setFont(PDType1Font.HELVETICA_BOLD, 15);
		contentStream.moveTextPositionByAmount(100, 680);
		contentStream.drawString("Statistik fuer jeden einzelnen Spieler");
		contentStream.endText();

		for (int i = 0; i < Players.values().length; ++i) {
			contentStream.beginText();
			contentStream.setFont(PDType1Font.HELVETICA_BOLD, 10);
			createIndividualContent(contentStream, Players.values()[i]);
			contentStream.endText();
			contentStream.close();
			if (i < Players.values().length - 1) {
				page = new PDPage();
				document.addPage(page);
				contentStream = new PDPageContentStream(document, page);
			}
		}
	}

	/**
	 * Write statistics to given contentStream of a pdf page.
	 *
	 * @param contentStream
	 *            The contentStream of the pdf page to write on.
	 * @throws IOException
	 */
	private void createOverallContent(PDPageContentStream contentStream)
			throws IOException {
		OverallStatistics data = gui.model.gameDB.getOverallStatistics();

		contentStream.moveTextPositionByAmount(50, 650);
		contentStream.drawString("#Spiele (ohne weiter): "
				+ data.getAnzahlSpieleGesamt() + " (gewonnen: "
				+ String.format("%.2f", data.getGesamtWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("#Rufspiele: " + data.getAnzahlRufspiele()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getRufspieleWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Rufspiel: "
				+ data.getTeuerstesRufspiel());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Soli gesamt: " + data.getAnzahlSoliGesamt()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliGesamtWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("#Soli normal: " + data.getAnzahlSoli()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliNormalWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo: "
				+ data.getTeuerstesSolo());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Solo Tout: " + data.getAnzahlSoliTout()
				+ " (gewonnen: "
				+ String.format("%.2f", data.getSoliToutWinPerc()) + "%)");

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo Tout: "
				+ data.getTeuerstesSoloTout());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Solo Sie: " + data.getAnzahlSoliSie());

		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("-> teuerstes Solo Sie: "
				+ data.getTeuerstesSoloSie());

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream.drawString("#Weiter: " + data.getAnzahlWeiter());
	}

	private void createIndividualContent(PDPageContentStream contentStream,
			Players player) throws IOException {
		contentStream.moveTextPositionByAmount(50, 650);
		contentStream.drawString(player.toString());

		contentStream.moveTextPositionByAmount(0, -22);

		PlayerWiseStatistics data = gui.model.getGameData()
				.getPlayerWiseStatistics(player);

		contentStream.drawString("Gespielte Spiele:");
		contentStream.moveTextPositionByAmount(50, -16);
		contentStream.drawString("- Gesamt: " + data.getGamesPlayedTot()
				+ ", davon gewonnen: " + data.getGamesWonTot() + " ("
				+ String.format("%.2f", data.getGamesWonPerc()) + "%)");

		for (Games game : Games.values()) {
			if (game != Games.WEITER && game != Games.NONE) {
				int i = game.ordinal();
				contentStream.moveTextPositionByAmount(0, -16);
				contentStream.drawString("- "
						+ game.toString()
						+ ": "
						+ data.getGamesPlayedPerType()[i]
						+ ", davon gewonnen: "
						+ data.getGamesWonPerType()[i]
						+ " ("
						+ String.format("%.2f",
								data.getGamesWonPerTypePerc()[i]) + "%");
			}
		}

		contentStream.moveTextPositionByAmount(-50, -16);
		contentStream
				.drawString("Höchster Kontostand: " + data.getHighestAcc());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Niedrigster Kontostand: "
				+ data.getLowestAcc());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Größter Gewinn: " + data.getHighestWin());

		contentStream.moveTextPositionByAmount(0, -16);
		contentStream.drawString("Größter Verlust: " + data.getHighestLoss());

		contentStream.moveTextPositionByAmount(0, -32);
	}

}