Fix LoggerCarrierAspect.aj

Fix LoggerCarrierAspect.aj

package org.slc.sli.aspect;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.CollectionOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.slc.sli.domain.Entity;
import org.slc.sli.domain.Repository;
import org.slc.sli.dal.repository.MongoRepository;

import org.slc.sli.common.util.logging.SecurityEvent;
import org.slc.sli.common.util.logging.LoggerCarrier;
import org.slc.sli.common.util.tenantdb.TenantContext;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

public aspect LoggerCarrierAspect {
	declare parents : (org.slc.sli.ingestion..* &&
            !java.lang.Enum+)  implements LoggerCarrier;

    private Repository<Entity> mongoEntityRepository;

    private MongoTemplate template;

    public MongoTemplate getTemplate() {
    	return template;
    }

    public void setTemplate(MongoTemplate template) {
    	this.template = template;
    }

    @Value("${sli.ingestion.securityEvent.capSize}")
    private String capSize;

    public void LoggerCarrier.audit(SecurityEvent event) {
        MongoRepository<Entity> mer = (MongoRepository<Entity>) LoggerCarrierAspect.aspectOf().getMongoEntityRepository();
        if (mer != null) {
            MongoTemplate mongoTemplate = mer.getTemplate();
            String capSizeStr = LoggerCarrierAspect.aspectOf().getCapSize();

            if (capSizeStr != null && !capSizeStr.isEmpty()) {
                int capSizeInt = Integer.parseInt(capSizeStr);
                // UN: If the collection is not present, create the capped collection.
                // However, if it is present and uncapped, change it to capped collection
                // 496 bytes is size of 1 security event document * capsize ~ the size that we want.
                if (!mongoTemplate.collectionExists("securityEvent")) {
                    CollectionOptions collectionOptions = new CollectionOptions(capSizeInt * 496, capSizeInt, true);
                    mongoTemplate.createCollection("securityEvent", collectionOptions);
                } else {
                    if (!mongoTemplate.getCollection("securityEvent").isCapped()) {
                        DBObject cmd = new BasicDBObject();
                        cmd.put("convertToCapped", "securityEvent");
                        cmd.put("size", capSizeInt * 496);
                        mongoTemplate.getDb().command(cmd);
                    }
                }
            }

            TenantContext.setIsSystemCall(true);

            Map<String, Object> metadata = new HashMap<String, Object>();
            metadata.put("tenantId", event.getTenantId());
            mer.create("securityEvent", event.getProperties(), metadata, "securityEvent");
        } else {
            LoggerFactory.getLogger("SecurityMonitor").info("[Could not log SecurityEvent to mongo!]");
        }

        switch (event.getLogLevel()) {
            case TYPE_DEBUG:
                LoggerFactory.getLogger("SecurityMonitor").debug(event.toString());
                break;

            case TYPE_WARN:
                LoggerFactory.getLogger("SecurityMonitor").warn(event.toString());
                break;

            case TYPE_INFO:
                LoggerFactory.getLogger("SecurityMonitor").info(event.toString());
                break;

            case TYPE_ERROR:
                LoggerFactory.getLogger("SecurityMonitor").error(event.toString());
                break;

            case TYPE_TRACE:
                LoggerFactory.getLogger("SecurityMonitor").trace(event.toString());
                break;

            default:
                LoggerFactory.getLogger("SecurityMonitor").info(event.toString());
                break;
        }
    }

    public Repository<Entity> getMongoEntityRepository() {
        return mongoEntityRepository;
    }

    public void setMongoEntityRepository(Repository<Entity> mongoEntityRepository) {
        this.mongoEntityRepository = mongoEntityRepository;
    }

    public String getCapSize() {
        return capSize;
    }

    public void setCapSize(String capSize) {
        this.capSize = capSize;
    }

}

package org.slc.sli.aspect;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.CollectionOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.slc.sli.domain.Entity;
import org.slc.sli.domain.Repository;
import org.slc.sli.dal.repository.MongoRepository;

import org.slc.sli.common.util.logging.SecurityEvent;
import org.slc.sli.common.util.logging.LoggerCarrier;
import org.slc.sli.common.util.tenantdb.TenantContext;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

public aspect LoggerCarrierAspect {
	declare parents : (org.slc.sli.ingestion..* &&
            !java.lang.Enum+)  implements LoggerCarrier;

    private Repository<Entity> mongoEntityRepository;

    @Value("${sli.ingestion.securityEvent.capSize}")
    private String capSize;

    public void LoggerCarrier.audit(SecurityEvent event) {
        MongoRepository<Entity> mer = (MongoRepository<Entity>) LoggerCarrierAspect.aspectOf().getMongoEntityRepository();
        if (mer != null) {
            MongoTemplate mongoTemplate = mer.getTemplate();
            String capSizeStr = LoggerCarrierAspect.aspectOf().getCapSize();

            if (capSizeStr != null && !capSizeStr.isEmpty()) {
                int capSizeInt = Integer.parseInt(capSizeStr);
                // UN: If the collection is not present, create the capped collection.
                // However, if it is present and uncapped, change it to capped collection
                // 496 bytes is size of 1 security event document * capsize ~ the size that we want.
                if (!mongoTemplate.collectionExists("securityEvent")) {
                    CollectionOptions collectionOptions = new CollectionOptions(capSizeInt * 496, capSizeInt, true);
                    mongoTemplate.createCollection("securityEvent", collectionOptions);
                } else {
                    if (!mongoTemplate.getCollection("securityEvent").isCapped()) {
                        DBObject cmd = new BasicDBObject();
                        cmd.put("convertToCapped", "securityEvent");
                        cmd.put("size", capSizeInt * 496);
                        mongoTemplate.getDb().command(cmd);
                    }
                }
            }

            TenantContext.setIsSystemCall(true);

            Map<String, Object> metadata = new HashMap<String, Object>();
            metadata.put("tenantId", event.getTenantId());
            mer.create("securityEvent", event.getProperties(), metadata, "securityEvent");
        } else {
            LoggerFactory.getLogger("SecurityMonitor").info("[Could not log SecurityEvent to mongo!]");
        }

        switch (event.getLogLevel()) {
            case TYPE_DEBUG:
                LoggerFactory.getLogger("SecurityMonitor").debug(event.toString());
                break;

            case TYPE_WARN:
                LoggerFactory.getLogger("SecurityMonitor").warn(event.toString());
                break;

            case TYPE_INFO:
                LoggerFactory.getLogger("SecurityMonitor").info(event.toString());
                break;

            case TYPE_ERROR:
                LoggerFactory.getLogger("SecurityMonitor").error(event.toString());
                break;

            case TYPE_TRACE:
                LoggerFactory.getLogger("SecurityMonitor").trace(event.toString());
                break;

            default:
                LoggerFactory.getLogger("SecurityMonitor").info(event.toString());
                break;
        }
    }

    public Repository<Entity> getMongoEntityRepository() {
        return mongoEntityRepository;
    }

    public void setMongoEntityRepository(Repository<Entity> mongoEntityRepository) {
        this.mongoEntityRepository = mongoEntityRepository;
    }

    public String getCapSize() {
        return capSize;
    }

    public void setCapSize(String capSize) {
        this.capSize = capSize;
    }

}


added sneaky throws hack

added sneaky throws hack

/**
 * Copyright 2010 CosmoCode GmbH
 *
 * 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 de.cosmocode.palava.jpa.aspectj;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.gag.annotation.remark.Hack;
import com.google.inject.Inject;
import com.google.inject.Provider;

import de.cosmocode.palava.core.aop.AbstractPalavaAspect;
import de.cosmocode.palava.jpa.Transactional;

public final aspect EntityTransactionAspect extends AbstractPalavaAspect issingleton() {

    private static final Logger LOG = LoggerFactory.getLogger(EntityTransactionAspect.class);

    private Provider<EntityManager> currentManager;

    @Inject
    public void setProvider(Provider<EntityManager> manager) {
        this.currentManager = Preconditions.checkNotNull(manager, "Manager");
    }

    pointcut transactional(): execution(@Transactional * *.*(..));

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        final EntityManager manager = currentManager.get();
        LOG.trace("Retrieved entitymanager {}", manager);
        final EntityTransaction tx = manager.getTransaction();
        LOG.trace("Using transaction {}", tx);

        final boolean local = !tx.isActive();

        if (local) {
            LOG.debug("Beginning automatic transaction {}", tx);
            tx.begin();
        } else {
            LOG.trace("Transaction {} already active", tx);
        }

        final Object returnValue;

        try {
            returnValue = proceed();
        } catch (Exception e) {
            try {
                if (local && (tx.isActive() || tx.getRollbackOnly())) {
                    LOG.info("Rolling back local/active transaction {}", tx);
                    tx.rollback();
                } else if (!tx.getRollbackOnly()) {
                    LOG.debug("Setting transaction {} as rollback only", tx);
                    tx.setRollbackOnly();
                }
            } catch (PersistenceException inner) {
                LOG.error("Rollback failed", inner);
            }

            // hack to support throwing checked exceptions
            return sneakyThrow(e);
        }

        if (local && tx.isActive()) {
            if (tx.getRollbackOnly()) {
                LOG.debug("Rolling back marked transaction {}", tx);
                tx.rollback();
            } else {
                try {
                    tx.commit();
                    LOG.trace("Committed automatic transaction {}", tx);
                } catch (PersistenceException e) {
                    try {
                        LOG.info("Rolling back transaction {}", tx);
                        tx.rollback();
                    } catch (PersistenceException inner) {
                        LOG.error("Rollback failed", inner);
                    }
                    throw e;
                }
            }
        } else {
            LOG.trace("Not committing non-local transaction {}", tx);
        }

        return returnValue;
    }

    @Hack("Why is this possible?")
    private Object sneakyThrow(Throwable t) {
        this.<RuntimeException>doSneakyThrow(t);
        return null;
    }

    @SuppressWarnings("unchecked")
    private <T extends Throwable> T doSneakyThrow(Throwable t) throws T {
        throw (T) t;
    }

}

/**
 * Copyright 2010 CosmoCode GmbH
 *
 * 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 de.cosmocode.palava.jpa.aspectj;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;

import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Provider;

import de.cosmocode.palava.core.aop.AbstractPalavaAspect;
import de.cosmocode.palava.jpa.Transactional;

public final aspect EntityTransactionAspect extends AbstractPalavaAspect issingleton() {

    private static final Logger LOG = LoggerFactory.getLogger(EntityTransactionAspect.class);

    private Provider<EntityManager> currentManager;

    @Inject
    public void setProvider(Provider<EntityManager> manager) {
        this.currentManager = Preconditions.checkNotNull(manager, "Manager");
    }

    pointcut transactional(): execution(@Transactional * *.*(..));

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        final EntityManager manager = currentManager.get();
        LOG.trace("Retrieved entitymanager {}", manager);
        final EntityTransaction tx = manager.getTransaction();
        LOG.trace("Using transaction {}", tx);
        final boolean localTx = !tx.isActive();

        if (localTx) {
            LOG.trace("Beginning automatic transaction {}", tx);
            tx.begin();
        } else {
            LOG.trace("Transaction {} already active", tx);
        }

        final Object returnValue;

        try {
            returnValue = proceed();
        } catch (RuntimeException e) {
            LOG.debug("Exception inside automatic transaction context; rolling back", e);
            tx.rollback();
            throw e;
        }

        if (localTx && tx.isActive()) {
            if (tx.getRollbackOnly()) {
                LOG.debug("Transaction {} was marked as rollback only. Rolling back...", tx);
                tx.rollback();
            } else {
                try {
                    tx.commit();
                    LOG.trace("Committed automatic transaction {}", tx);
                } catch (PersistenceException e) {
                    LOG.debug("Commit in automatic transaction context failed", e);
                    if (tx.isActive()) {
                        LOG.debug("Rolling back {}", tx);
                        try {
                            tx.rollback();
                        } catch (PersistenceException e2) {
                            LOG.error("Commit in automatic transaction context failed", e);
                            throw e2;
                        }
                    } else {
                        LOG.debug("Can't roll back inactive transaction {}", tx);
                    }
                    throw e;
                }
            }
        } else {
            LOG.trace("Not committing non-local transaction {}", tx);
        }

        return returnValue;
    }

}


refactor StatOverallTxt

refactor StatOverallTxt

import java.awt.GridLayout;

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

import view.GUI;
import view.UIUpdater;
import model.db.GameData;
import model.SystemValues.WIN;
import model.db.DataObject;

public privileged aspect StatOverallTxt {

    private static GUI gui;
    private static JPanel panel = new JPanel();
    private static JTextArea statText = new JTextArea();

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

    after(JTabbedPane tabbedPane):
			execution(public static void StatisticsHelper.StatisticsPaneCreated(JTabbedPane))
			&& args(tabbedPane) {
        statText.setEditable(false);
        panel.setLayout(new GridLayout(0, 1));
        panel.add(statText);
        ((JTabbedPane) tabbedPane).addTab("OverallText", panel);
    }

    after() : execution(* UIUpdater.run()) {
        statText.setText(getOverallStatisticsString());
    }

    public String getOverallStatisticsString() {
        OverallStatistics data = gui.model.getGameData().getOverallStatistics();

        int anzahlSpieleGesamt = data.getAnzahlSpieleGesamt();
        int anzahlSpieleGesamtGewonnen = data.getAnzahlSpieleGesamtGewonnen();
        int teuerstesRufspiel = data.getTeuerstesRufspiel();
        int teuerstesSolo = data.getTeuerstesSolo();
        int teuerstesSoloTout = data.getTeuerstesSoloTout();
        int teuerstesSoloSie = data.getTeuerstesSoloSie();
        int anzahlRufspiele = data.getAnzahlRufspiele();
        int anzahlSoli = data.getAnzahlSoli();
        int anzahlSoliTout = data.getAnzahlSoliTout();
        int anzahlSoliSie = data.getAnzahlSoliSie();
        int anzahlSoliGesamt = data.getAnzahlSoliGesamt();
        int anzahlGewonneneSoliGesamt = data.getAnzahlGewonneneSoliGesamt();
        int anzahlGewonneneRufspiele = data.getAnzahlGewonneneRufspiele();
        int anzahlGewonneneSoli = data.getAnzahlGewonneneSoli();
        int anzahlGewonneneSoliTout = data.getAnzahlGewonneneSoliTout();
        int anzahlGewonneneSoliSie = data.getAnzahlGewonneneSoliSie();
        int anzahlWeiter = data.getAnzahlWeiter();

        double sologesamtwin = (anzahlSoliGesamt) > 0 ? ((double) (anzahlGewonneneSoliGesamt) / (anzahlSoliGesamt))
                : 0;

        return "#Spiele (ohne weiter): "
                + anzahlSpieleGesamt
                + " (gewonnen: "
                + String.format("%.2f",
                        (anzahlSpieleGesamt > 0 ? anzahlSpieleGesamtGewonnen
                                / ((double) anzahlSpieleGesamt) : 0) * 100)
                + "%)\n"
                + "#Rufspiele: "
                + anzahlRufspiele
                + " (gewonnen: "
                + String.format("%.2f",
                        (anzahlRufspiele > 0 ? anzahlGewonneneRufspiele
                                / ((double) anzahlRufspiele) : 0) * 100)
                + "%)\n"
                + "          -> teurstes Rufspiel: "
                + teuerstesRufspiel
                + "\n"
                + "#Soli gesamt: "
                + (anzahlSoli + anzahlSoliTout + anzahlSoliSie)
                + " (gewonnen: "
                + String.format("%.2f", sologesamtwin * 100)
                + "%)\n"
                + "#Soli normal: "
                + anzahlSoli
                + " (gewonnen: "
                + String.format("%.2f", (anzahlSoli > 0 ? anzahlGewonneneSoli
                        / ((double) anzahlSoli) : 0) * 100)
                + "%)\n"
                + "            -> teurstes Solo: "
                + teuerstesSolo
                + "\n"
                + "#Solo Tout: "
                + anzahlSoliTout
                + " (gewonnen: "
                + String.format("%.2f",
                        (anzahlSoliTout > 0 ? anzahlGewonneneSoliTout
                                / ((double) anzahlSoliTout) : 0) * 100)
                + "%)\n"
                + "          -> teurstes Solo Tout: "
                + teuerstesSoloTout
                + "\n"
                + "#Solo Sie: "
                + anzahlSoliSie
                + " (gewonnen: "
                + String.format("%.2f",
                        (anzahlSoliSie > 0 ? anzahlGewonneneSoliSie
                                / ((double) anzahlSoliSie) : 0) * 100) + "%)\n"
                + "         -> teurstes Solo Sie: " + teuerstesSoloSie + "\n"
                + "#Weiter: " + anzahlWeiter;
    }

    public OverallStatistics GameData.getOverallStatistics() {
        int anzahlSpieleGesamt = 0;
        int anzahlSpieleGesamtGewonnen = 0;
        int teuerstesRufspiel = 0;
        int teuerstesSolo = 0;
        int teuerstesSoloTout = 0;
        int teuerstesSoloSie = 0;
        int anzahlRufspiele = 0;
        int anzahlSoli = 0;
        int anzahlSoliTout = 0;
        int anzahlSoliSie = 0;
        int anzahlSoliGesamt = 0;
        int anzahlGewonneneSoliGesamt = 0;
        int anzahlGewonneneRufspiele = 0;
        int anzahlGewonneneSoli = 0;
        int anzahlGewonneneSoliTout = 0;
        int anzahlGewonneneSoliSie = 0;
        int anzahlWeiter = -1;

        for (DataObject obj : data) {
            switch (obj.getGameKind()) {
            case RUFSPIEL:
                anzahlRufspiele++;
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneRufspiele++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesRufspiel) {
                    teuerstesRufspiel = obj.getGameValue();
                }
                break;
            case SOLO:
                anzahlSoli++;
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneSoli++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesSolo) {
                    teuerstesSolo = obj.getGameValue();
                }
                break;
            case TOUT:
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneSoliTout++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesSoloTout) {
                    teuerstesSoloTout = obj.getGameValue();
                }
                anzahlSoliTout++;
                break;
            case SIE:
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneSoliSie++;
                    anzahlSpieleGesamtGewonnen++;
                }
                anzahlSoliSie++;
                if (obj.getGameValue() > teuerstesSoloSie) {
                    teuerstesSoloSie = obj.getGameValue();
                }
                break;
            case WEITER:
                anzahlWeiter++;
                break;
            case NONE: // nothing to do here
                break;
            default: // here neither
                break;
            }
        }

        anzahlSoliGesamt = anzahlSoli + anzahlSoliTout + anzahlSoliSie;
        anzahlGewonneneSoliGesamt = anzahlGewonneneSoli
                + anzahlGewonneneSoliSie + anzahlGewonneneSoliTout;

        return new OverallStatistics(anzahlSpieleGesamt,
                anzahlSpieleGesamtGewonnen, anzahlRufspiele,
                anzahlGewonneneRufspiele, anzahlSoli, anzahlGewonneneSoli,
                anzahlSoliTout, anzahlGewonneneSoliTout, anzahlSoliSie,
                anzahlGewonneneSoliSie, anzahlSoliGesamt,
                anzahlGewonneneSoliGesamt, anzahlWeiter, teuerstesRufspiel,
                teuerstesSolo, teuerstesSoloTout, teuerstesSoloSie);
    }
}

class OverallStatistics {

    private int anzahlSpieleGesamt;
    private int anzahlSpieleGesamtGewonnen;
    private int anzahlRufspiele;
    private int anzahlGewonneneRufspiele;
    private int anzahlSoli;
    private int anzahlGewonneneSoli;
    private int anzahlSoliTout;
    private int anzahlGewonneneSoliTout;
    private int anzahlSoliSie;
    private int anzahlGewonneneSoliSie;
    private int anzahlSoliGesamt;
    private int anzahlGewonneneSoliGesamt;
    private int anzahlWeiter;
    private int teuerstesRufspiel = 0;
    private int teuerstesSolo = 0;
    private int teuerstesSoloTout = 0;
    private int teuerstesSoloSie = 0;

    public OverallStatistics(int anzahlSpieleGesamt,
            int anzahlSpieleGesamtGewonnen, int anzahlRufspiele,
            int anzahlGewonneneRufspiele, int anzahlSoli,
            int anzahlGewonneneSoli, int anzahlSoliTout,
            int anzahlGewonneneSoliTout, int anzahlSoliSie,
            int anzahlGewonneneSoliSie, int anzahlSoliGesamt,
            int anzahlGewonneneSoliGesamt, int anzahlWeiter,
            int teuerstesRufspiel, int teuerstesSolo, int teuerstesSoloTout,
            int teuerstesSoloSie) {
        this.anzahlSpieleGesamt = anzahlSpieleGesamt;
        this.anzahlSpieleGesamtGewonnen = anzahlSpieleGesamtGewonnen;
        this.anzahlRufspiele = anzahlRufspiele;
        this.anzahlGewonneneRufspiele = anzahlGewonneneRufspiele;
        this.anzahlSoli = anzahlSoli;
        this.anzahlGewonneneSoli = anzahlGewonneneSoli;
        this.anzahlSoliTout = anzahlSoliTout;
        this.anzahlGewonneneSoliTout = anzahlGewonneneSoliTout;
        this.anzahlSoliSie = anzahlSoliSie;
        this.anzahlGewonneneSoliSie = anzahlGewonneneSoliSie;
        this.anzahlSoliGesamt = anzahlSoliGesamt;
        this.anzahlGewonneneSoliGesamt = anzahlGewonneneSoliGesamt;
        this.anzahlWeiter = anzahlWeiter;
        this.teuerstesRufspiel = teuerstesRufspiel;
        this.teuerstesSolo = teuerstesSolo;
        this.teuerstesSoloTout = teuerstesSoloTout;
        this.teuerstesSoloSie = teuerstesSoloSie;
    }

    public int getAnzahlSpieleGesamt() {
        return anzahlSpieleGesamt;
    }

    public int getAnzahlSpieleGesamtGewonnen() {
        return anzahlSpieleGesamtGewonnen;
    }

    public int getAnzahlRufspiele() {
        return anzahlRufspiele;
    }

    public int getAnzahlGewonneneRufspiele() {
        return anzahlGewonneneRufspiele;
    }

    public int getAnzahlSoli() {
        return anzahlSoli;
    }

    public int getAnzahlGewonneneSoli() {
        return anzahlGewonneneSoli;
    }

    public int getAnzahlSoliTout() {
        return anzahlSoliTout;
    }

    public int getAnzahlGewonneneSoliTout() {
        return anzahlGewonneneSoliTout;
    }

    public int getAnzahlSoliSie() {
        return anzahlSoliSie;
    }

    public int getAnzahlGewonneneSoliSie() {
        return anzahlGewonneneSoliSie;
    }

    public int getAnzahlSoliGesamt() {
        return anzahlSoliGesamt;
    }

    public int getAnzahlGewonneneSoliGesamt() {
        return anzahlGewonneneSoliGesamt;
    }

    public int getAnzahlWeiter() {
        return anzahlWeiter;
    }

    public int getTeuerstesRufspiel() {
        return teuerstesRufspiel;
    }

    public int getTeuerstesSolo() {
        return teuerstesSolo;
    }

    public int getTeuerstesSoloTout() {
        return teuerstesSoloTout;
    }

    public int getTeuerstesSoloSie() {
        return teuerstesSoloSie;
    }
}

import java.awt.GridLayout;

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

import view.GUI;
import view.UIUpdater;
import model.db.GameData;
import model.SystemValues.WIN;
import model.db.DataObject;

public privileged aspect StatOverallTxt {

    private static GUI gui;
    private static JPanel panel = new JPanel();
    private static JTextArea statText = new JTextArea();

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

    after(JTabbedPane tabbedPane):
			execution(public static void StatisticsHelper.StatisticsPaneCreated(JTabbedPane))
			&& args(tabbedPane) {
        statText.setEditable(false);
        panel.setLayout(new GridLayout(0, 1));
        panel.add(statText);
        ((JTabbedPane) tabbedPane).addTab("OverallText", panel);
    }

    after() : execution(* UIUpdater.run()) {
        statText.setText(gui.model.getGameData().getOverallStatisticsString());
    }

    public String GameData.getOverallStatisticsString() {
        int anzahlSpieleGesamt = 0;
        int anzahlSpieleGesamtGewonnen = 0;
        int teuerstesRufspiel = 0;
        int teuerstesSolo = 0;
        int teuerstesSoloTout = 0;
        int teuerstesSoloSie = 0;
        int anzahlRufspiele = 0;
        int anzahlSolo = 0;
        int anzahlSoloTout = 0;
        int anzahlSoloSie = 0;
        int anzahlGewonneneRufspiele = 0;
        int anzahlGewonneneSoli = 0;
        int anzahlGewonneneSoliTout = 0;
        int anzahlWeiter = -1;

        for (DataObject obj : data) {
            switch (obj.getGameKind()) {
            case RUFSPIEL:
                anzahlRufspiele++;
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneRufspiele++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesRufspiel) {
                    teuerstesRufspiel = obj.getGameValue();
                }
                break;
            case SOLO:
                anzahlSolo++;
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneSoli++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesSolo) {
                    teuerstesSolo = obj.getGameValue();
                }
                break;
            case TOUT:
                anzahlSpieleGesamt++;
                if (obj.getGameWon() == WIN.PLAYER) {
                    anzahlGewonneneSoliTout++;
                    anzahlSpieleGesamtGewonnen++;
                }
                if (obj.getGameValue() > teuerstesSoloTout) {
                    teuerstesSoloTout = obj.getGameValue();
                }
                anzahlSoloTout++;
                break;
            case SIE:
                anzahlSpieleGesamt++;
                anzahlSpieleGesamtGewonnen++;
                anzahlSoloSie++;
                if (obj.getGameValue() > teuerstesSoloSie) {
                    teuerstesSoloSie = obj.getGameValue();
                }
                break;
            case WEITER:
                anzahlWeiter++;
                break;
            case NONE: // nothing to do here
                break;
            default: // here neither
                break;
            }
        }

        double sologesamtwin = (anzahlSolo + anzahlSoloSie + anzahlSoloTout) > 0 ? ((anzahlGewonneneSoli
                + anzahlGewonneneSoliTout + anzahlSoloSie) / 1.0 / (anzahlSolo
                + anzahlSoloSie + anzahlSoloTout))
                : 0;

        return "#Spiele (ohne weiter): "
                + anzahlSpieleGesamt
                + " (gewonnen: "
                + String.format("%.2f", (anzahlSpieleGesamt > 0 ? anzahlSpieleGesamtGewonnen
                        / ((double) anzahlSpieleGesamt) : 0) * 100)
                + "%)\n"
                + "#Rufspiele: "
                + anzahlRufspiele
                + " (gewonnen: "
                + String.format("%.2f", (anzahlRufspiele > 0 ? anzahlGewonneneRufspiele
                        / ((double) anzahlRufspiele) : 0) * 100)
                + "%)\n"
                + "          -> teurstes Rufspiel: "
                + teuerstesRufspiel
                + "\n"
                + "#Soli gesamt: "
                + (anzahlSolo + anzahlSoloTout + anzahlSoloSie)
                + " (gewonnen: "
                + String.format("%.2f", sologesamtwin * 100)
                + "%)\n"
                + "#Soli normal: "
                + anzahlSolo
                + " (gewonnen: "
                + String.format("%.2f", (anzahlSolo > 0 ? anzahlGewonneneSoli / ((double) anzahlSolo)
                        : 0) * 100)
                + "%)\n"
                + "            -> teurstes Solo: "
                + teuerstesSolo
                + "\n"
                + "#Solo Tout: "
                + anzahlSoloTout
                + " (gewonnen: "
                + String.format("%.2f", (anzahlSoloTout > 0 ? anzahlGewonneneSoliTout
                        / ((double) anzahlSoloTout) : 0) * 100) + "%)\n"
                + "          -> teurstes Solo Tout: " + teuerstesSoloTout
                + "\n" + "#Solo Sie: " + anzahlSoloSie + "\n"
                + "         -> teurstes Solo Sie: " + teuerstesSoloSie + "\n"
                + "#Weiter: " + anzahlWeiter;
    }
}


Fixed SPR-6734 by resticting record/replay logic to only entity methods that originated in a test method

package org.springframework.mock.staticmock;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Abstract aspect to enable mocking of methods picked out by a pointcut.
 * Sub-aspects must define the mockStaticsTestMethod() pointcut to
 * indicate call stacks when mocking should be triggered, and the
 * methodToMock() pointcut to pick out a method invocations to mock.
 *
 * @author Rod Johnson
 * @author Ramnivas Laddad
 *
 */
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {

	protected abstract pointcut mockStaticsTestMethod();

	protected abstract pointcut methodToMock();

	private boolean recording = true;

	static enum CallResponse { nothing, return_, throw_ };

	// Represents a list of expected calls to static entity methods
	// Public to allow inserted code to access: is this normal??
	public class Expectations {

		// Represents an expected call to a static entity method
		private class Call {
			private final String signature;
			private final Object[] args;

			private Object responseObject; // return value or throwable
			private CallResponse responseType = CallResponse.nothing;

			public Call(String name, Object[] args) {
				this.signature = name;
				this.args = args;
			}

			public boolean hasResponseSpecified() {
				return responseType != CallResponse.nothing;
			}

			public void setReturnVal(Object retVal) {
				this.responseObject = retVal;
				responseType = CallResponse.return_;
			}

			public void setThrow(Throwable throwable) {
				this.responseObject = throwable;
				responseType = CallResponse.throw_;
			}

			public Object returnValue(String lastSig, Object[] args) {
				checkSignature(lastSig, args);
				return responseObject;
			}

			public Object throwException(String lastSig, Object[] args) {
				checkSignature(lastSig, args);
				throw (RuntimeException)responseObject;
			}

			private void checkSignature(String lastSig, Object[] args) {
				if (!signature.equals(lastSig)) {
					throw new IllegalArgumentException("Signature doesn't match");
				}
				if (!Arrays.equals(this.args, args)) {
					throw new IllegalArgumentException("Arguments don't match");
				}
			}
		}

		private List<Call> calls = new LinkedList<Call>();

		// Calls already verified
		private int verified;

		public void verify() {
			if (verified != calls.size()) {
				throw new IllegalStateException("Expected " + calls.size()
						+ " calls, received " + verified);
			}
		}

		/**
		 * Validate the call and provide the expected return value
		 * @param lastSig
		 * @param args
		 * @return
		 */
		public Object respond(String lastSig, Object[] args) {
			Call call = nextCall();
			CallResponse responseType = call.responseType;
			if (responseType == CallResponse.return_) {
				return call.returnValue(lastSig, args);
			} else if(responseType == CallResponse.throw_) {
				return (RuntimeException)call.throwException(lastSig, args);
			} else if(responseType == CallResponse.nothing) {
				// do nothing
			}
			throw new IllegalStateException("Behavior of " + call + " not specified");
		}

		private Call nextCall() {
			if (verified > calls.size() - 1) {
				throw new IllegalStateException("Expected " + calls.size()
						+ " calls, received " + verified);
			}
			return calls.get(verified++);
		}

		public void expectCall(String lastSig, Object lastArgs[]) {
			Call call = new Call(lastSig, lastArgs);
			calls.add(call);
		}

		public boolean hasCalls() {
			return !calls.isEmpty();
		}

		public void expectReturn(Object retVal) {
			Call call = calls.get(calls.size() - 1);
			if (call.hasResponseSpecified()) {
				throw new IllegalStateException("No static method invoked before setting return value");
			}
			call.setReturnVal(retVal);
		}

		public void expectThrow(Throwable throwable) {
			Call call = calls.get(calls.size() - 1);
			if (call.hasResponseSpecified()) {
				throw new IllegalStateException("No static method invoked before setting throwable");
			}
			call.setThrow(throwable);
		}
	}

	private Expectations expectations = new Expectations();

	after() returning : mockStaticsTestMethod() {
		if (recording && (expectations.hasCalls())) {
			throw new IllegalStateException(
					"Calls recorded, yet playback state never reached: Create expectations then call "
							+ this.getClass().getSimpleName() + ".playback()");
		}
		expectations.verify();
	}

	Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
		if (recording) {
			expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
			// Return value doesn't matter
			return null;
		} else {
			return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
		}
	}

	public void expectReturnInternal(Object retVal) {
		if (!recording) {
			throw new IllegalStateException("Not recording: Cannot set return value");
		}
		expectations.expectReturn(retVal);
	}

	public void expectThrowInternal(Throwable throwable) {
		if (!recording) {
			throw new IllegalStateException("Not recording: Cannot set throwable value");
		}
		expectations.expectThrow(throwable);
	}

	public void playbackInternal() {
		recording = false;
	}

}

package org.springframework.mock.staticmock;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Abstract aspect to enable mocking of methods picked out by a pointcut.
 * Sub-aspects must define the mockStaticsTestMethod() pointcut to
 * indicate call stacks when mocking should be triggered, and the
 * methodToMock() pointcut to pick out a method invocations to mock.
 *
 * @author Rod Johnson
 * @author Ramnivas Laddad
 *
 */
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {

	protected abstract pointcut mockStaticsTestMethod();

	protected abstract pointcut methodToMock();

	private boolean recording = true;

	static enum CallResponse { nothing, return_, throw_ };

	// Represents a list of expected calls to static entity methods
	// Public to allow inserted code to access: is this normal??
	public class Expectations {

		// Represents an expected call to a static entity method
		private class Call {
			private final String signature;
			private final Object[] args;

			private Object responseObject; // return value or throwable
			private CallResponse responseType = CallResponse.nothing;

			public Call(String name, Object[] args) {
				this.signature = name;
				this.args = args;
			}

			public boolean hasResponseSpecified() {
				return responseType != CallResponse.nothing;
			}

			public void setReturnVal(Object retVal) {
				this.responseObject = retVal;
				responseType = CallResponse.return_;
			}

			public void setThrow(Throwable throwable) {
				this.responseObject = throwable;
				responseType = CallResponse.throw_;
			}

			public Object returnValue(String lastSig, Object[] args) {
				checkSignature(lastSig, args);
				return responseObject;
			}

			public Object throwException(String lastSig, Object[] args) {
				checkSignature(lastSig, args);
				throw (RuntimeException)responseObject;
			}

			private void checkSignature(String lastSig, Object[] args) {
				if (!signature.equals(lastSig)) {
					throw new IllegalArgumentException("Signature doesn't match");
				}
				if (!Arrays.equals(this.args, args)) {
					throw new IllegalArgumentException("Arguments don't match");
				}
			}
		}

		private List<Call> calls = new LinkedList<Call>();

		// Calls already verified
		private int verified;

		public void verify() {
			if (verified != calls.size()) {
				throw new IllegalStateException("Expected " + calls.size()
						+ " calls, received " + verified);
			}
		}

		/**
		 * Validate the call and provide the expected return value
		 * @param lastSig
		 * @param args
		 * @return
		 */
		public Object respond(String lastSig, Object[] args) {
			Call call = nextCall();
			CallResponse responseType = call.responseType;
			if (responseType == CallResponse.return_) {
				return call.returnValue(lastSig, args);
			} else if(responseType == CallResponse.throw_) {
				return (RuntimeException)call.throwException(lastSig, args);
			} else if(responseType == CallResponse.nothing) {
				// do nothing
			}
			throw new IllegalStateException("Behavior of " + call + " not specified");
		}

		private Call nextCall() {
			if (verified > calls.size() - 1) {
				throw new IllegalStateException("Expected " + calls.size()
						+ " calls, received " + verified);
			}
			return calls.get(verified++);
		}

		public void expectCall(String lastSig, Object lastArgs[]) {
			Call call = new Call(lastSig, lastArgs);
			calls.add(call);
		}

		public boolean hasCalls() {
			return !calls.isEmpty();
		}

		public void expectReturn(Object retVal) {
			Call call = calls.get(calls.size() - 1);
			if (call.hasResponseSpecified()) {
				throw new IllegalStateException("No static method invoked before setting return value");
			}
			call.setReturnVal(retVal);
		}

		public void expectThrow(Throwable throwable) {
			Call call = calls.get(calls.size() - 1);
			if (call.hasResponseSpecified()) {
				throw new IllegalStateException("No static method invoked before setting throwable");
			}
			call.setThrow(throwable);
		}
	}

	private Expectations expectations = new Expectations();

	after() returning : mockStaticsTestMethod() {
		if (recording && (expectations.hasCalls())) {
			throw new IllegalStateException(
					"Calls recorded, yet playback state never reached: Create expectations then call "
							+ this.getClass().getSimpleName() + ".playback()");
		}
		expectations.verify();
	}

	Object around() : methodToMock() {
		if (recording) {
			expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
			// Return value doesn't matter
			return null;
		} else {
			return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
		}
	}

	public void expectReturnInternal(Object retVal) {
		if (!recording) {
			throw new IllegalStateException("Not recording: Cannot set return value");
		}
		expectations.expectReturn(retVal);
	}

	public void expectThrowInternal(Throwable throwable) {
		if (!recording) {
			throw new IllegalStateException("Not recording: Cannot set throwable value");
		}
		expectations.expectThrow(throwable);
	}

	public void playbackInternal() {
		recording = false;
	}

}


refactoring do código de disparo de notificações

package br.eti.rslemos.brill.events;

import java.util.ArrayList;
import java.util.List;

import br.eti.rslemos.brill.Rule;
import br.eti.rslemos.brill.RuleBasedTagger;
import br.eti.rslemos.tagger.Sentence;

@SuppressWarnings("unchecked")
public aspect RuleBasedTaggerObserver extends RuleBasedTaggerEvents perthis(this(RuleBasedTagger+)) {

	private List<RuleBasedTaggerListener> listeners = new ArrayList<RuleBasedTaggerListener>();

	public void RuleBasedTagger.addRuleBasedTaggerListener(RuleBasedTaggerListener listener) {
		aspectOf(this).listeners.add(listener);
	}

	public void RuleBasedTagger.removeRuleBasedTaggerListener(RuleBasedTaggerListener listener) {
		aspectOf(this).listeners.remove(listener);
	}

	private static interface Method<T, A> {
		void invoke(T target, A argument);
	}

	private void fireNotification(Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> method, RuleBasedTaggerEvent prototype) {
		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				method.invoke(listener, event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> TAGGINGSENTENCE =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.taggingSentence(argument);
			}
	};

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> SENTENCETAGGED =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.sentenceTagged(argument);
			}
	};

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> BEFOREBASETAGGER =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.beforeBaseTagger(argument);
			}
	};

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> AFTERBASETAGGER =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.afterBaseTagger(argument);
			}
	};

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> BEFORERULEAPPLICATION =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.beforeRuleApplication(argument);
			}
	};

	private static final Method<RuleBasedTaggerListener, RuleBasedTaggerEvent> AFTERRULEAPPLICATION =
		new Method<RuleBasedTaggerListener, RuleBasedTaggerEvent>() {
			public void invoke(RuleBasedTaggerListener target, RuleBasedTaggerEvent argument) {
				target.afterRuleApplication(argument);
			}
	};

	before(RuleBasedTagger tagger, Sentence sentence): onTagSentence(tagger, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		fireNotification(TAGGINGSENTENCE, prototype);
	}

	after(RuleBasedTagger tagger, Sentence sentence) returning: onTagSentence(tagger, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		fireNotification(SENTENCETAGGED, prototype);
	}

	before(RuleBasedTagger tagger, Sentence sentence): onBaseTagger(tagger, *, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		fireNotification(BEFOREBASETAGGER, prototype);
	}

	after(RuleBasedTagger tagger, Sentence sentence) returning: onBaseTagger(tagger, *, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		fireNotification(AFTERBASETAGGER, prototype);
	}

	before(RuleBasedTagger tagger, Rule rule, Sentence sentence): onRuleApplication(tagger, rule, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);
		prototype.setActingRule(rule);

		fireNotification(BEFORERULEAPPLICATION, prototype);
	}

	after(RuleBasedTagger tagger, Rule rule, Sentence sentence) returning: onRuleApplication(tagger, rule, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);
		prototype.setActingRule(rule);

		fireNotification(AFTERRULEAPPLICATION, prototype);
	}

}

package br.eti.rslemos.brill.events;

import java.util.ArrayList;
import java.util.List;

import br.eti.rslemos.brill.Rule;
import br.eti.rslemos.brill.RuleBasedTagger;
import br.eti.rslemos.tagger.Sentence;

@SuppressWarnings("unchecked")
public aspect RuleBasedTaggerObserver extends RuleBasedTaggerEvents perthis(this(RuleBasedTagger+)) {

	private List<RuleBasedTaggerListener> listeners = new ArrayList<RuleBasedTaggerListener>();

	public void RuleBasedTagger.addRuleBasedTaggerListener(RuleBasedTaggerListener listener) {
		aspectOf(this).listeners.add(listener);
	}

	public void RuleBasedTagger.removeRuleBasedTaggerListener(RuleBasedTaggerListener listener) {
		aspectOf(this).listeners.remove(listener);
	}

	before(RuleBasedTagger tagger, Sentence sentence): onTagSentence(tagger, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.taggingSentence(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	after(RuleBasedTagger tagger, Sentence sentence) returning: onTagSentence(tagger, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.sentenceTagged(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	before(RuleBasedTagger tagger, Sentence sentence): onBaseTagger(tagger, *, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.beforeBaseTagger(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	after(RuleBasedTagger tagger, Sentence sentence) returning: onBaseTagger(tagger, *, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.afterBaseTagger(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	before(RuleBasedTagger tagger, Rule rule, Sentence sentence): onRuleApplication(tagger, rule, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);
		prototype.setActingRule(rule);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.beforeRuleApplication(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

	after(RuleBasedTagger tagger, Rule rule, Sentence sentence) returning: onRuleApplication(tagger, rule, sentence) {
		RuleBasedTaggerEvent prototype = new RuleBasedTaggerEvent(tagger);
		prototype.setOnSentence(sentence);
		prototype.setActingRule(rule);

		for (RuleBasedTaggerListener listener : listeners) {
			RuleBasedTaggerEvent event = (RuleBasedTaggerEvent) prototype.clone();
			try {
				listener.afterRuleApplication(event);
			} catch (Throwable t) {
				// swallow
			}
		}
	}

}