moved sneakyThrow to finally block

moved sneakyThrow to finally block

/**
 * 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 * *.*(..));

    @SuppressWarnings("finally")
    @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.debug("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);
            } finally {
                // 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.debug("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.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.debug("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.debug("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;
    }

}


journal LinkedHashMap/LinkedHashSet

journal LinkedHashMap/LinkedHashSet

/*
 * hashshmash - An aspect to record HashMap/Set allocations
 * Copyright 2013 MeBigFatGuy.com
 * Copyright 2013 Dave Brosius
 *
 * 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 com.mebigfatguy.hashshmash;

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

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map<?,?> m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Map<?,?> m): call(LinkedHashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new LinkedHashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(HashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new HashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(LinkedHashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new LinkedHashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 5 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashDetails, HashDetails> hDetails = new ConcurrentHashMap<HashDetails, HashDetails>();
    private PrintWriter writer;
    private boolean operational = false;

    public Journaller() {
        try {
            System.out.println("*************************");
            System.out.println("HASHSHMASH ASPECT ENABLED");
            System.out.println("*************************");

            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

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

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

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

    public void add(HashDetails details) {
        if (operational)
            hDetails.put(details,  details);
    }

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

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

abstract class HashDetails {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss-SSS");

    public Date allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public abstract Map<?,?> getMap();

    public abstract String getDetailType();

    public String toString() {
        return getDetailType() + "\t" + FORMATTER.format(allocTime) + "\t" + caller + "\t" + getMap().size() + "\t" + totalSlots + "\t" + usedSlots;
    }
}

class HashMapDetails extends HashDetails {
    public Map<?, ?> map;

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

    public Map<?,?> getMap() {
        return map;
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class LinkedHashMapDetails extends HashMapDetails {
    public Map<?, ?> map;

    public LinkedHashMapDetails(Map<?, ?> m, Date d, String c) {
       super(m, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class HashSetDetails extends HashDetails {
    private static Field MAP_FIELD;
    static {
        try {
            MAP_FIELD = HashSet.class.getDeclaredField("map");
            MAP_FIELD.setAccessible(true);
        } catch (Exception e) {
            MAP_FIELD = null;
        }
    }

    public Set<?> set;

    public HashSetDetails(Set<?> s, Date d, String c) {
        set = s;
        allocTime = d;
        caller = c;
        size = set.size();
    }

    public Map<?,?> getMap() {
        try {
            if (MAP_FIELD == null)
                return null;

            return (Map<?,?>) MAP_FIELD.get(set);
        } catch (Exception e) {
            return null;
        }
    }

    public String getDetailType() {
        return set.getClass().getSimpleName();
    }
}

class LinkedHashSetDetails extends HashSetDetails {
    public Map<?, ?> map;

    public LinkedHashSetDetails(Set<?> s, Date d, String c) {
       super(s, d, c);
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

/*
 * hashshmash - An aspect to record HashMap/Set allocations
 * Copyright 2013 MeBigFatGuy.com
 * Copyright 2013 Dave Brosius
 *
 * 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 com.mebigfatguy.hashshmash;

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

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map<?,?> m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set<?> s): call(HashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new HashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 5 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashDetails, HashDetails> hDetails = new ConcurrentHashMap<HashDetails, HashDetails>();
    private PrintWriter writer;
    private boolean operational = false;

    public Journaller() {
        try {
            System.out.println("*************************");
            System.out.println("HASHSHMASH ASPECT ENABLED");
            System.out.println("*************************");

            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

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

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

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

    public void add(HashDetails details) {
        if (operational)
            hDetails.put(details,  details);
    }

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

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

abstract class HashDetails {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss-SSS");

    public Date allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public abstract Map<?,?> getMap();

    public abstract String getDetailType();

    public String toString() {
        return getDetailType() + "\t" + FORMATTER.format(allocTime) + "\t" + caller + "\t" + getMap().size() + "\t" + totalSlots + "\t" + usedSlots;
    }
}

class HashMapDetails extends HashDetails {
    public Map<?, ?> map;

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

    public Map<?,?> getMap() {
        return map;
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class HashSetDetails extends HashDetails {
    private static Field MAP_FIELD;
    static {
        try {
            MAP_FIELD = HashSet.class.getDeclaredField("map");
            MAP_FIELD.setAccessible(true);
        } catch (Exception e) {
            MAP_FIELD = null;
        }
    }

    public Set<?> set;

    public HashSetDetails(Set<?> s, Date d, String c) {
        set = s;
        allocTime = d;
        caller = c;
        size = set.size();
    }

    public Map<?,?> getMap() {
        try {
            if (MAP_FIELD == null)
                return null;

            return (Map<?,?>) MAP_FIELD.get(set);
        } catch (Exception e) {
            return null;
        }
    }

    public String getDetailType() {
        return set.getClass().getSimpleName();
    }
}


Added location accuracy to logs

Added location accuracy to logs

/*
 * Copyright 2011 Google Inc.
 *
 * 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.
 *
 * This code has been modified by Stefano Dacchille.
 */

package com.github.ignition.location;

import org.aspectj.lang.annotation.SuppressAjWarnings;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.github.ignition.location.annotations.IgnitedLocation;
import com.github.ignition.location.annotations.IgnitedLocationActivity;
import com.github.ignition.location.receivers.IgnitedLocationChangedReceiver;
import com.github.ignition.location.receivers.IgnitedPassiveLocationChangedReceiver;
import com.github.ignition.location.tasks.IgnitedLastKnownLocationAsyncTask;
import com.github.ignition.location.templates.ILastLocationFinder;
import com.github.ignition.location.templates.IgnitedAbstractLastLocationFinder;
import com.github.ignition.location.templates.IgnitedAbstractLocationUpdateRequester;
import com.github.ignition.location.templates.OnIgnitedLocationChangedListener;
import com.github.ignition.location.utils.PlatformSpecificImplementationFactory;
import com.github.ignition.support.IgnitedDiagnostics;

@SuppressAjWarnings
public aspect IgnitedLocationManager {
    public static final String LOG_TAG = IgnitedLocationManager.class.getSimpleName();

    declare parents : (@IgnitedLocationActivity *) implements OnIgnitedLocationChangedListener;

    private Criteria defaultCriteria, lowPowerCriteria;
    protected IgnitedAbstractLocationUpdateRequester locationUpdateRequester;
    protected PendingIntent locationListenerPendingIntent, locationListenerPassivePendingIntent;
    protected LocationManager locationManager;
    protected IgnitedLocationListener bestInactiveLocationProviderListener;

    private Context context;
    private volatile Location currentLocation;

    private IgnitedLastKnownLocationAsyncTask ignitedLastKnownLocationTask;
    private SharedPreferences prefs;
    private Handler handler;

    private long locationUpdatesInterval, passiveLocationUpdatesInterval;
    private int locationUpdatesDistanceDiff;
    private int passiveLocationUpdatesDistanceDiff;
    private boolean requestLocationUpdates;
    private boolean locationUpdatesDisabled = true;

    // Switch to another provider if gps doesn't return a location quickly enough.
    private Runnable removeGpsUpdates = new Runnable() {
        @Override
        public void run() {
            Log.d(LOG_TAG,
                    "It looks like GPS isn't available at this time (i.e.: maybe you're indoors). Removing GPS location updates and requesting network updates.");

            disableLocationUpdates(false);
            requestLocationUpdates(context, lowPowerCriteria());
        }
    };

    /**
     * If the Location Provider we're using to receive location updates is disabled while the app is
     * running, this Receiver will be notified, allowing us to re-register our Location Receivers
     * using the best available Location Provider is still available.
     */
    protected BroadcastReceiver locationProviderDisabledReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            boolean providerDisabled = !intent.getBooleanExtra(
                    LocationManager.KEY_PROVIDER_ENABLED, false);
            // Re-register the location listeners using the best available
            // Location Provider.
            if (providerDisabled) {
                disableLocationUpdates(false);
                requestLocationUpdates(context, null);
            }
        }
    };

    /**
     * If the battery state is low disable the passive location update receiver.
     */
    protected BroadcastReceiver refreshLocationUpdatesReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            disableLocationUpdates(false);
            requestLocationUpdates(context, null);
        }
    };

    after(Context context, IgnitedLocationActivity ignitedAnnotation) :
        execution(* Activity.onCreate(..)) && this(context)
        && @this(ignitedAnnotation) && within(@IgnitedLocationActivity *) {

        // Get a reference to the Context
        this.context = context;
        // Set pref file
        prefs = context.getSharedPreferences(IgnitedLocationConstants.SHARED_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
        // Get references to the managers
        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        handler = new Handler();

        // Specify the Criteria to use when requesting location updates while
        // the application is Active
        if (defaultCriteria == null) {
            defaultCriteria = new Criteria();
        }
        // Use gps if it's enabled and if battery level is at least 15%
        boolean useGps = prefs.getBoolean(IgnitedLocationConstants.SP_KEY_LOCATION_UPDATES_USE_GPS,
                IgnitedLocationConstants.USE_GPS_DEFAULT);
        if (useGps) {
            defaultCriteria.setAccuracy(Criteria.ACCURACY_FINE);
        } else {
            defaultCriteria.setPowerRequirement(Criteria.POWER_LOW);
        }

        // Setup the location update Pending Intent
        Intent activeIntent = new Intent(IgnitedLocationConstants.ACTIVE_LOCATION_UPDATE_ACTION);
        locationListenerPendingIntent = PendingIntent.getBroadcast(context, 0, activeIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        // Setup the passive location update Pending Intent
        Intent passiveIntent = new Intent(context, IgnitedPassiveLocationChangedReceiver.class);
        locationListenerPassivePendingIntent = PendingIntent.getBroadcast(context, 0,
                passiveIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        // Instantiate a Location Update Requester class based on the available
        // platform version. This will be used to request location updates.
        locationUpdateRequester = PlatformSpecificImplementationFactory
                .getLocationUpdateRequester(context);
    }

    private boolean isBatteryOk() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = context.registerReceiver(null, filter);
        double currentLevel = 100.0;
        if (intent != null) {
            currentLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        }

        return currentLevel >= prefs.getInt(IgnitedLocationConstants.SP_KEY_MIN_BATTERY_LEVEL,
                IgnitedLocationConstants.MIN_BATTERY_LEVEL_FOR_GPS_DEFAULT);
    }

    before(Context context, IgnitedLocationActivity ignitedAnnotation) :
        execution(* Activity.onResume(..)) && this(context)
        && @this(ignitedAnnotation) && within(@IgnitedLocationActivity *) {
        // Get a reference to the Context if this context is null
        if (this.context == null) {
            this.context = context;
        }

        saveToPreferences(context, ignitedAnnotation);

        Log.d(LOG_TAG, "Retrieving last known location...");
        // Get the last known location. This isn't directly affecting the UI, so put it on a
        // worker thread.
        if (ignitedLastKnownLocationTask == null) {
            ignitedLastKnownLocationTask = new IgnitedLastKnownLocationAsyncTask(context,
                    locationUpdatesDistanceDiff, locationUpdatesInterval);
            ignitedLastKnownLocationTask.execute();
        }
    }

    /**
     * Save last settings to preferences.
     *
     * @param context
     * @param locationAnnotation
     */
    private void saveToPreferences(Context context, IgnitedLocationActivity locationAnnotation) {
        requestLocationUpdates = locationAnnotation.requestLocationUpdates();
        locationUpdatesDistanceDiff = locationAnnotation.locationUpdatesDistanceDiff();
        locationUpdatesInterval = locationAnnotation.locationUpdatesInterval();
        passiveLocationUpdatesDistanceDiff = locationAnnotation
                .passiveLocationUpdatesDistanceDiff();
        passiveLocationUpdatesInterval = locationAnnotation.passiveLocationUpdatesInterval();
        boolean enablePassiveLocationUpdates = locationAnnotation.enablePassiveUpdates();
        boolean useGps = locationAnnotation.useGps();

        Editor editor = prefs.edit();
        editor.putBoolean(IgnitedLocationConstants.SP_KEY_ENABLE_LOCATION_UPDATES,
                requestLocationUpdates);
        editor.putBoolean(IgnitedLocationConstants.SP_KEY_ENABLE_PASSIVE_LOCATION_UPDATES,
                enablePassiveLocationUpdates);
        editor.putBoolean(IgnitedLocationConstants.SP_KEY_LOCATION_UPDATES_USE_GPS, useGps);
        editor.putInt(IgnitedLocationConstants.SP_KEY_LOCATION_UPDATES_DISTANCE_DIFF,
                locationUpdatesDistanceDiff);
        editor.putLong(IgnitedLocationConstants.SP_KEY_LOCATION_UPDATES_INTERVAL,
                locationUpdatesInterval);
        editor.putInt(IgnitedLocationConstants.SP_KEY_PASSIVE_LOCATION_UPDATES_DISTANCE_DIFF,
                passiveLocationUpdatesDistanceDiff);
        editor.putLong(IgnitedLocationConstants.SP_KEY_PASSIVE_LOCATION_UPDATES_INTERVAL,
                passiveLocationUpdatesInterval);
        editor.putBoolean(IgnitedLocationConstants.SP_KEY_RUN_ONCE, true);
        editor.putInt(IgnitedLocationConstants.SP_KEY_MIN_BATTERY_LEVEL,
                locationAnnotation.minBatteryLevelForGps());
        editor.putLong(IgnitedLocationConstants.SP_KEY_WAIT_FOR_GPS_FIX_INTERVAL,
                locationAnnotation.waitForGpsFixInterval());
        editor.putBoolean(IgnitedLocationConstants.SP_KEY_SHOW_WAIT_FOR_LOCATION_DIALOG,
                locationAnnotation.showWaitForLocationDialog());
        editor.commit();

    }

    before(Activity activity, IgnitedLocationActivity ignitedAnnotation) : execution(* Activity.onPause(..))
        && @this(ignitedAnnotation) && this(activity) && within(@IgnitedLocationActivity *) {

        if (ignitedAnnotation.requestLocationUpdates()) {
            disableLocationUpdates(true);
            handler.removeCallbacks(removeGpsUpdates);
        }

        ignitedLastKnownLocationTask.getLastLocationFinder().cancel();

        boolean finishing = activity.isFinishing();
        if (finishing) {
            if (ignitedLastKnownLocationTask != null) {
                ignitedLastKnownLocationTask.cancel(true);
                ignitedLastKnownLocationTask = null;
            }
            context = null;
        }
    }

    Location around() : get(@IgnitedLocation Location *) {
        return currentLocation;
    }

    void around(Location freshLocation) : set(@IgnitedLocation Location *) && args(freshLocation)
        && within(IgnitedPassiveLocationChangedReceiver) && !adviceexecution() {

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, lng/acc): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude() + "/"
                + currentLocation.getAccuracy());
    }

    void around(Location freshLocation) : set(@IgnitedLocation Location *) && args(freshLocation)
        && (within(IgnitedLocationChangedReceiver) || within(IgnitedAbstractLastLocationFinder)
                || within(IgnitedLastKnownLocationAsyncTask)) && !adviceexecution() {

        if (context == null) {
            return;
        }
        final Activity activity = (Activity) context;
        boolean showWaitForLocationDialog = prefs.getBoolean(
                IgnitedLocationConstants.SP_KEY_SHOW_WAIT_FOR_LOCATION_DIALOG,
                IgnitedLocationConstants.SHOW_WAIT_FOR_LOCATION_DIALOG_DEFAULT);
        if (freshLocation == null) {
            if (showWaitForLocationDialog) {
                activity.showDialog(R.id.ign_loc_dialog_wait_for_fix);
            }
            return;
        }

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, lng/acc): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude() + "/" + currentLocation.getAccuracy());
        boolean keepRequestingLocationUpdates = ((OnIgnitedLocationChangedListener) context)
                .onIgnitedLocationChanged(currentLocation);
        Bundle extras = freshLocation.getExtras();
        // a) If location updates shouldn't be requested anymore turn them off.
        // b) Don't turn location updates on if last location is too old, since the single location
        // update is running.
        if (!keepRequestingLocationUpdates) {
            disableLocationUpdates(true);
            // PlatformSpecificImplementationFactory.getLastLocationFinder(context).cancel();
            return;
        } else if (requestLocationUpdates
                && !extras.containsKey(ILastLocationFinder.LAST_LOCATION_TOO_OLD_OR_INACCURATE_EXTRA)) {
            // If we requested location updates, turn them on here.
            requestLocationUpdates(context, null);
        }

        // If gps is enabled location comes from gps, remove runnable that removes gps updates
        boolean lastLocation = extras.containsKey(IgnitedLocationConstants.IGNITED_LAST_LOCATION_EXTRA);
        if (!lastLocation && defaultCriteria.getAccuracy() == Criteria.ACCURACY_FINE
                && currentLocation.getProvider().equals(LocationManager.GPS_PROVIDER)) {
            handler.removeCallbacks(removeGpsUpdates);
        }
    }

    /**
     * Start listening for location updates.
     */
    protected void requestLocationUpdates(Context context, Criteria criteria) {
        if (!locationUpdatesDisabled) {
            return;
        }
        Criteria locationUpdateCriteria = criteria;
        if (criteria == null) {
            if (isBatteryOk()) {
                locationUpdateCriteria = defaultCriteria;
            } else {
                locationUpdateCriteria = lowPowerCriteria();
            }
        }
        Log.d(LOG_TAG, "Disabling passive location updates");
        locationManager.removeUpdates(locationListenerPassivePendingIntent);

        Log.d(LOG_TAG, "Requesting location updates");
        // Normal updates while activity is visible.
        locationUpdateRequester.requestLocationUpdates(locationUpdatesInterval,
                locationUpdatesDistanceDiff, locationUpdateCriteria, locationListenerPendingIntent);

        // Register a receiver that listens for when the provider I'm using has
        // been disabled.
        IntentFilter locationProviderDisabledIntentFilter = new IntentFilter(
                IgnitedLocationConstants.ACTIVE_LOCATION_UPDATE_PROVIDER_DISABLED_ACTION);
        context.registerReceiver(locationProviderDisabledReceiver,
                locationProviderDisabledIntentFilter);

        IntentFilter refreshLocationUpdatesIntentFilter = new IntentFilter(
                IgnitedLocationConstants.UPDATE_LOCATION_UPDATES_CRITERIA_ACTION);
        context.registerReceiver(refreshLocationUpdatesReceiver, refreshLocationUpdatesIntentFilter);

        // Register a receiver that listens for when a better provider than I'm
        // using becomes available.
        String bestProvider = locationManager.getBestProvider(locationUpdateCriteria, false);
        String bestAvailableProvider = locationManager.getBestProvider(locationUpdateCriteria, true);
        if (bestProvider != null && !bestProvider.equals(bestAvailableProvider)) {
            bestInactiveLocationProviderListener = new IgnitedLocationListener(context);
            locationManager.requestLocationUpdates(bestProvider, 0, 0,
                    bestInactiveLocationProviderListener, context.getMainLooper());
        }

        if (bestAvailableProvider.equals(LocationManager.GPS_PROVIDER)) {
            Log.d(LOG_TAG, "Posting delayed remove GPS updates message");
            // Post a runnable that will remove gps updates if no gps location is returned after 1
            // minute in order to avoid draining the battery.
            handler.postDelayed(removeGpsUpdates, prefs.getLong(
                    IgnitedLocationConstants.SP_KEY_WAIT_FOR_GPS_FIX_INTERVAL,
                    IgnitedLocationConstants.WAIT_FOR_GPS_FIX_INTERVAL_DEFAULT));
        }

        locationUpdatesDisabled = false;
    }

    /**
     * Stop listening for location updates
     *
     * @param enablePassiveLocationUpdates
     */
    protected void disableLocationUpdates(boolean requestPassiveLocationUpdates) {
        if (locationUpdatesDisabled) {
            return;
        }

        Log.d(LOG_TAG, "Disabling location updates");
        context.unregisterReceiver(locationProviderDisabledReceiver);
        context.unregisterReceiver(refreshLocationUpdatesReceiver);

        locationUpdateRequester.removeLocationUpdates();
        if (bestInactiveLocationProviderListener != null) {
            locationManager.removeUpdates(bestInactiveLocationProviderListener);
        }

        boolean finishing = ((Activity) context).isFinishing();

        if (requestPassiveLocationUpdates && !finishing) {
            requestPassiveLocationUpdates();
        }

        locationUpdatesDisabled = true;
    }

    private void requestPassiveLocationUpdates() {
        if (IgnitedDiagnostics.SUPPORTS_FROYO
                && prefs.getBoolean(
                        IgnitedLocationConstants.SP_KEY_ENABLE_PASSIVE_LOCATION_UPDATES,
                        IgnitedLocationConstants.ENABLE_PASSIVE_LOCATION_UPDATES_DEFAULT)) {
            Log.d(LOG_TAG, "Requesting passive location updates");
            // Passive location updates from 3rd party apps when the Activity isn't
            // visible. Only for Android 2.2+.
            locationUpdateRequester.requestPassiveLocationUpdates(passiveLocationUpdatesInterval,
                    passiveLocationUpdatesDistanceDiff, locationListenerPassivePendingIntent);
        }
    }

    public boolean isLocationUpdatesDisabled() {
        return locationUpdatesDisabled;
    }

    public Criteria lowPowerCriteria() {
        if (lowPowerCriteria == null) {
            lowPowerCriteria = new Criteria();
            lowPowerCriteria.setPowerRequirement(Criteria.POWER_LOW);
            lowPowerCriteria.setAccuracy(Criteria.NO_REQUIREMENT);
        }
        return lowPowerCriteria;
    }

    /**
     * If the best Location Provider (usually GPS) is not available when we request location
     * updates, this listener will be notified if / when it becomes available. It calls
     * requestLocationUpdates to re-register the location listeners using the better Location
     * Provider.
     */
    private class IgnitedLocationListener implements LocationListener {
        private Context context;

        public IgnitedLocationListener(Context appContext) {
            this.context = appContext;
        }

        @Override
        public void onLocationChanged(Location l) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
            // Re-register the location listeners using the better Location
            // Provider.
            disableLocationUpdates(false);
            requestLocationUpdates(context, null);
        }
    }

}


added comments

added comments

/**
 * 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.jta;

import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

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.Registry;
import de.cosmocode.palava.core.aop.AbstractPalavaAspect;

public abstract aspect AbstractUserTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<UserTransaction> provider;

    private TransactionBeginEvent begin;
    private TransactionBeganEvent began;
    private TransactionCommitEvent commit;
    private TransactionCommittedEvent committed;
    private TransactionRollbackEvent rollback;
    private TransactionRolledbackEvent rolledback;

    @Inject
    void setProvider(Provider<UserTransaction> provider) {
        this.provider = Preconditions.checkNotNull(provider, "Provider");
    }

    @Inject
    void setRegistry(Registry registry) {
        Preconditions.checkNotNull(registry, "Registry");
        this.begin = registry.proxy(TransactionBeginEvent.class);
        this.began = registry.proxy(TransactionBeganEvent.class);
        this.commit = registry.proxy(TransactionCommitEvent.class);
        this.committed = registry.proxy(TransactionCommittedEvent.class);
        this.rollback = registry.proxy(TransactionRollbackEvent.class);
        this.rolledback = registry.proxy(TransactionRolledbackEvent.class);
    }

    protected abstract pointcut transactional();

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        Preconditions.checkNotNull(provider, "Provider not injected yet");
        final UserTransaction tx = provider.get();
        LOG.trace("Using transaction {}", tx);

        try {
            LOG.trace("Status of transaction: {}", tx.getStatus());
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        int status;
        final boolean local;
        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        local = status == Status.STATUS_NO_TRANSACTION;

        if (local) {
            LOG.debug("Beginning automatic transaction {}", tx);
            try {
                begin.eventTransactionBegin(tx);
                tx.begin();
                began.eventTransactionBegan(tx);
            } catch (NotSupportedException e) {
                throw new IllegalStateException(e);
            } catch (SystemException e) {
                throw new IllegalStateException(e);
            }
        } else {
            LOG.trace("Transaction {} already active (Status: {})", tx, status);
        }

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        final Object returnValue;

        try {
            LOG.trace("Status before execution: {}", status);
            returnValue = proceed();
        } catch (Exception e) {
            try {
                if (local &&
                    (tx.getStatus() == Status.STATUS_ACTIVE || tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)) {
                    LOG.info("Rolling back local/active transaction {}", tx);
                    rollback(tx);
                } else if (tx.getStatus() != Status.STATUS_ROLLEDBACK || tx.getStatus() != Status.STATUS_ROLLING_BACK) {
                    LOG.debug("Setting transaction {} as rollback only", tx);
                    tx.setRollbackOnly();
                }
            } catch (Exception inner) {
                LOG.error("Rollback failed", inner);
            }

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

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        LOG.trace("Status after execution: {}", status);

        if (local) {
            if (status == Status.STATUS_MARKED_ROLLBACK) {
                try {
                    LOG.debug("Rolling back marked transaction {}", tx);
                    rollback(tx);
                } catch (SystemException e) {
                    throw new IllegalStateException(e);
                }
            } else {
                try {
                    commit.eventTransactionCommit(tx);
                    tx.commit();
                    committed.eventTransactionCommitted(tx);
                    LOG.debug("Committed automatic transaction {}", tx);
                } catch (Exception e) {
                    try {
                        LOG.info("Rolling back transaction {}", tx);
                        rollback(tx);
                    } catch (Exception inner) {
                        LOG.error("Rollback failed", inner);
                    }
                    throw new IllegalStateException(e);
                }
            }
        }

        return returnValue;
    }

    private void rollback(UserTransaction tx) throws SystemException {
        rollback.eventTransactionRollback(tx);
        tx.rollback();
        rolledback.eventTransactionRolledback(tx);
    }

    @Hack("Why is this possible?")
    private RuntimeException 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.jta;

import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

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.Registry;
import de.cosmocode.palava.core.aop.AbstractPalavaAspect;

public abstract aspect AbstractUserTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<UserTransaction> provider;

    private TransactionBeginEvent begin;
    private TransactionBeganEvent began;
    private TransactionCommitEvent commit;
    private TransactionCommittedEvent committed;
    private TransactionRollbackEvent rollback;
    private TransactionRolledbackEvent rolledback;

    @Inject
    void setProvider(Provider<UserTransaction> provider) {
        this.provider = Preconditions.checkNotNull(provider, "Provider");
    }

    @Inject
    void setRegistry(Registry registry) {
        Preconditions.checkNotNull(registry, "Registry");
        this.begin = registry.proxy(TransactionBeginEvent.class);
        this.began = registry.proxy(TransactionBeganEvent.class);
        this.commit = registry.proxy(TransactionCommitEvent.class);
        this.committed = registry.proxy(TransactionCommittedEvent.class);
        this.rollback = registry.proxy(TransactionRollbackEvent.class);
        this.rolledback = registry.proxy(TransactionRolledbackEvent.class);
    }

    protected abstract pointcut transactional();

    @SuppressAjWarnings("adviceDidNotMatch")
    Object around(): transactional() {
        Preconditions.checkNotNull(provider, "Provider not injected yet");
        final UserTransaction tx = provider.get();
        LOG.trace("Using transaction {}", tx);

        try {
            LOG.trace("Status of transaction: {}", tx.getStatus());
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        int status;
        final boolean local;
        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        local = status == Status.STATUS_NO_TRANSACTION;

        if (local) {
            LOG.debug("Beginning automatic transaction {}", tx);
            try {
                begin.eventTransactionBegin(tx);
                tx.begin();
                began.eventTransactionBegan(tx);
            } catch (NotSupportedException e) {
                throw new IllegalStateException(e);
            } catch (SystemException e) {
                throw new IllegalStateException(e);
            }
        } else {
            LOG.trace("Transaction {} already active (Status: {})", tx, status);
        }

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        final Object returnValue;

        try {
            LOG.trace("Status before execution: {}", status);
            returnValue = proceed();
        } catch (Exception e) {
            try {
                if (local &&
                    (tx.getStatus() == Status.STATUS_ACTIVE || tx.getStatus() == Status.STATUS_MARKED_ROLLBACK)) {
                    LOG.info("Rolling back local/active transaction {}", tx);
                    rollback(tx);
                } else if (tx.getStatus() != Status.STATUS_ROLLEDBACK || tx.getStatus() != Status.STATUS_ROLLING_BACK) {
                    LOG.debug("Setting transaction {} as rollback only", tx);
                    tx.setRollbackOnly();
                }
            } catch (Exception inner) {
                LOG.error("Rollback failed", inner);
            }
            // FIXME this effectively shadows the real exceptions thus preventing correct exception handling
            //throw new IllegalStateException(e);
            return sneakyThrow(e);
        }

        try {
            status = tx.getStatus();
        } catch (SystemException e) {
            throw new IllegalStateException(e);
        }

        LOG.trace("Status after execution: {}", status);

        if (local) {
            if (status == Status.STATUS_MARKED_ROLLBACK) {
                try {
                    LOG.debug("Rolling back marked transaction {}", tx);
                    rollback(tx);
                } catch (SystemException e) {
                    throw new IllegalStateException(e);
                }
            } else {
                try {
                    commit.eventTransactionCommit(tx);
                    tx.commit();
                    committed.eventTransactionCommitted(tx);
                    LOG.debug("Committed automatic transaction {}", tx);
                } catch (Exception e) {
                    try {
                        LOG.info("Rolling back transaction {}", tx);
                        rollback(tx);
                    } catch (Exception inner) {
                        LOG.error("Rollback failed", inner);
                    }
                    throw new IllegalStateException(e);
                }
            }
        }

        return returnValue;
    }

    private void rollback(UserTransaction tx) throws SystemException {
        rollback.eventTransactionRollback(tx);
        tx.rollback();
        rolledback.eventTransactionRolledback(tx);
    }

    private RuntimeException sneakyThrow(Throwable t) {
        this.<RuntimeException>doSneakyThrow(t);
        return null;
    }

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

}


update details.newSize

update details.newSize

package com.mebigfatguy.hashshmash;

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

import org.aspectj.lang.Signature;

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

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

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

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 10 * 1000;

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

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

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

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

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

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

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

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

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

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

package com.mebigfatguy.hashshmash;

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

import org.aspectj.lang.Signature;

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

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

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

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 10 * 1000;

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

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

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

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

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

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

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

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

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

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


add support for HashSet

add support for HashSet

package com.mebigfatguy.hashshmash;

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

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    after() returning (Set s): call(HashSet.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashSetDetails details = new HashSetDetails(s, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 5 * 1000;

    private Field tableField;
    private ConcurrentHashMap<HashDetails, HashDetails> hDetails = new ConcurrentHashMap<HashDetails, HashDetails>();
    private PrintWriter writer;

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

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

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

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

    public void add(HashDetails details) {
        hDetails.put(details,  details);
    }

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

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

abstract class HashDetails {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

    public Date allocTime;
    public String caller;
    public int size;
    public int usedSlots;
    public int totalSlots;

    public abstract Map<?,?> getMap();

    public abstract String getDetailType();

    public String toString() {
        return getDetailType() + "\t" + FORMATTER.format(allocTime) + "\t" + caller + "\t" + getMap().size() + "\t" + totalSlots + "\t" + usedSlots;
    }
}

class HashMapDetails extends HashDetails {
    public Map<?, ?> map;

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

    public Map<?,?> getMap() {
        return map;
    }

    public String getDetailType() {
        return map.getClass().getSimpleName();
    }
}

class HashSetDetails extends HashDetails {
    private static Field MAP_FIELD;
    static {
        try {
            MAP_FIELD = HashSet.class.getDeclaredField("map");
            MAP_FIELD.setAccessible(true);
        } catch (Exception e) {
            MAP_FIELD = null;
        }
    }

    public Set<?> set;

    public HashSetDetails(Set<?> s, Date d, String c) {
        set = s;
        allocTime = d;
        caller = c;
        size = set.size();
    }

    public Map<?,?> getMap() {
        try {
            if (MAP_FIELD == null)
                return null;

            return (Map<?,?>) MAP_FIELD.get(set);
        } catch (Exception e) {
            return null;
        }
    }

    public String getDetailType() {
        return set.getClass().getSimpleName();
    }
}

package com.mebigfatguy.hashshmash;

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

public aspect HashCollector {

    private static final Journaller journaller = new Journaller();

    after() returning (Map m): call(HashMap.new(..)) {
        String fileName = thisJoinPointStaticPart.getSourceLocation().getFileName();
        int line = thisJoinPointStaticPart.getSourceLocation().getLine();

        HashMapDetails details = new HashMapDetails(m, new Date(), fileName + ":" + line);
        journaller.add(details);
    }

    before(): execution(public static void *.main(String[])) {
        Class<?> c = HashCollector.class;
    }
}

final class Journaller implements Runnable {

    private static final int SLEEP_TIME = 10 * 1000;

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

    public Journaller() {
        try {

            tableField = HashMap.class.getDeclaredField("table");
            tableField.setAccessible(true);

            formatter = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
            File dir = new File(System.getProperty("user.home"), ".hashshmash");
            dir.mkdirs();

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

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

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

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

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

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

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


Updated the around pointcuts.

Updated the around pointcuts.

The important issue is to ensure that the lock/unlock methods and the
monitor steps are performed atomically.

This still might not be the best approach - it seems artifical as we
lock an object whilst locking it (tryLock). Perhaps it would be better
protected by the monitor object, but if tryLock is false this introduces
unnecessary contention.

package benchmark.competition.java.jUnitRV_MMT.monitoring;

import java.util.concurrent.locks.Lock;

import monitoring.impl.MonitorFactory;
import monitoring.intf.Monitor;
import properties.Property;
import properties.competition.JavaRV_mmt;
import structure.impl.other.Verdict;
import structure.intf.QEA;
import benchmark.competition.java.jUnitRV_MMT.ExampleLocking;

public aspect JUnitRV_MMTThreeAspect {

	private final Monitor monitor;

	private final int RUN = 1;
	private final int LOCK_TRUE = 2;
	private final int UNLOCK = 3;
	private final int ACTION = 4;

	public JUnitRV_MMTThreeAspect() {
		QEA qea = new JavaRV_mmt().make(Property.JAVARV_MMT_THREE);
		monitor = MonitorFactory.create(qea);
	}

	pointcut run(ExampleLocking thread) : execution(void ExampleLocking.run())
		&& target(thread);

	pointcut action(ExampleLocking thread) : call(void ExampleLocking.action())
		&& target(thread);

	before(ExampleLocking thread) : run(thread) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(RUN, thread);
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [thread="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

	boolean around(Lock lockObj, ExampleLocking thread) :
			call(boolean Lock.tryLock())
			&& cflow(call(boolean ExampleLocking.lock())) && target(lockObj)
			&& this(thread) {

		boolean result = false;
		// We perform the lock and the monitor step as an atomic action
		// i.e. whilst holding the lockObj, so that we cannot be interrupted
		synchronized (lockObj) {
			result = proceed(lockObj, thread);
			if (result) {
				Verdict verdict = null;
				// Ordering between lockObj and monitor important
				synchronized (monitor) {
					verdict = monitor.step(LOCK_TRUE, thread);
				}
				if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
					System.err
							.println("Violation in JUnitRV (MMT) 3. [thread="
									+ thread
									+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
				}

			}
		}
		return result;
	};

	void around(Lock lockObj, ExampleLocking thread) :
		call(void Lock.unlock()) && cflow(call(void ExampleLocking.unlock()))
		&& target(lockObj) && this(thread) {

		// We perform the unlock and the monitor step as an atomic action
		// i.e. whilst holding the lockObj, so that we cannot be interrupted
		Verdict verdict = null;
		synchronized (lockObj) {
			proceed(lockObj, thread);
			// Ordering between lockObj and monitor important
			synchronized (monitor) {
				verdict = monitor.step(LOCK_TRUE, thread);
			}
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [thread="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

	before(ExampleLocking thread) : action(thread) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(ACTION, thread);
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [id="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

}

package benchmark.competition.java.jUnitRV_MMT.monitoring;

import java.util.concurrent.locks.Lock;

import monitoring.impl.MonitorFactory;
import monitoring.intf.Monitor;
import properties.Property;
import properties.competition.JavaRV_mmt;
import structure.impl.other.Verdict;
import structure.intf.QEA;
import benchmark.competition.java.jUnitRV_MMT.ExampleLocking;

public aspect JUnitRV_MMTThreeAspect {

	private final Monitor monitor;

	private final int RUN = 1;
	private final int LOCK_TRUE = 2;
	private final int UNLOCK = 3;
	private final int ACTION = 4;

	public JUnitRV_MMTThreeAspect() {
		QEA qea = new JavaRV_mmt().make(Property.JAVARV_MMT_THREE);
		monitor = MonitorFactory.create(qea);
	}

	pointcut run(ExampleLocking thread) : execution(void ExampleLocking.run())
		&& target(thread);

	pointcut action(ExampleLocking thread) : call(void ExampleLocking.action())
		&& target(thread);

	before(ExampleLocking thread) : run(thread) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(RUN, thread);
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [thread="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

	boolean around(Lock lockObj, ExampleLocking thread) :
			call(boolean Lock.tryLock())
			&& cflow(call(boolean ExampleLocking.lock())) && target(lockObj)
			&& this(thread) {

		boolean result = false;
		synchronized (lockObj) {
			result = proceed(lockObj, thread); // TODO Not sure if this is right
		}
		if (result) {
			Verdict verdict = null;
			synchronized (monitor) {
				verdict = monitor.step(LOCK_TRUE, thread);
			}
			if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
				System.err
						.println("Violation in JUnitRV (MMT) 3. [thread="
								+ thread
								+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
			}

		}
		return result;
	};

	void around(Lock lockObj, ExampleLocking thread) :
		call(void Lock.unlock()) && cflow(call(void ExampleLocking.unlock()))
		&& target(lockObj) && this(thread) {

		synchronized (lockObj) {
			proceed(lockObj, thread); // TODO Not sure if this is right
		}
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(LOCK_TRUE, thread);
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [thread="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

	before(ExampleLocking thread) : action(thread) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(ACTION, thread);
		}
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JUnitRV (MMT) 3. [id="
							+ thread
							+ "]. - A thread has to call lock (returning true) to acquire the lock before it may call action - A call to lock only returns true, if no thread is currently holding the lock.");
		}
	};

}


Fixed a small annoying Roo bug on generics

// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).

package com.searchbox.domain;

import com.searchbox.domain.Definition;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;

privileged aspect Definition_Roo_Jpa_ActiveRecord {

    @PersistenceContext
    transient EntityManager Definition.entityManager;

    public static final List<String> Definition.fieldNames4OrderClauseFilter = java.util.Arrays.asList("clazz", "attributes");

    public static final EntityManager Definition.entityManager() {
        EntityManager em = new Definition() {
        }.entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

    public static long Definition.countDefinitions() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Definition o", Long.class).getSingleResult();
    }

    public static List<Definition> Definition.findAllDefinitions() {
        return entityManager().createQuery("SELECT o FROM Definition o", Definition.class).getResultList();
    }

    public static List<Definition> Definition.findAllDefinitions(String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM Definition o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, Definition.class).getResultList();
    }

    public static Definition Definition.findDefinition(Long id) {
        if (id == null) return null;
        return entityManager().find(Definition.class, id);
    }

    public static List<Definition> Definition.findDefinitionEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Definition o", Definition.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

    public static List<Definition> Definition.findDefinitionEntries(int firstResult, int maxResults, String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM Definition o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, Definition.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

    @Transactional
    public void Definition.persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

    @Transactional
    public void Definition.remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Definition attached = Definition.findDefinition(this.id);
            this.entityManager.remove(attached);
        }
    }

    @Transactional
    public void Definition.flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }

    @Transactional
    public void Definition.clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }

    @Transactional
    public Definition Definition.merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        Definition merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }

}

// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).

package com.searchbox.domain;

import com.searchbox.domain.Definition;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;

privileged aspect Definition_Roo_Jpa_ActiveRecord {

    @PersistenceContext
    transient EntityManager Definition.entityManager;

    public static final List<String> Definition.fieldNames4OrderClauseFilter = java.util.Arrays.asList("clazz", "attributes");

    public static final EntityManager Definition.entityManager() {
        EntityManager em = new Definition() {
        }.entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

    public static long Definition.countDefinitions() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Definition o", Long.class).getSingleResult();
    }

    public static List<Definition<Object>> Definition.findAllDefinitions() {
        return entityManager().createQuery("SELECT o FROM Definition o", Definition.class).getResultList();
    }

    public static List<Definition<Object>> Definition.findAllDefinitions(String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM Definition o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, Definition.class).getResultList();
    }

    public static Definition<Object> Definition.findDefinition(Long id) {
        if (id == null) return null;
        return entityManager().find(Definition.class, id);
    }

    public static List<Definition<Object>> Definition.findDefinitionEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Definition o", Definition.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

    public static List<Definition<Object>> Definition.findDefinitionEntries(int firstResult, int maxResults, String sortFieldName, String sortOrder) {
        String jpaQuery = "SELECT o FROM Definition o";
        if (fieldNames4OrderClauseFilter.contains(sortFieldName)) {
            jpaQuery = jpaQuery + " ORDER BY " + sortFieldName;
            if ("ASC".equalsIgnoreCase(sortOrder) || "DESC".equalsIgnoreCase(sortOrder)) {
                jpaQuery = jpaQuery + " " + sortOrder;
            }
        }
        return entityManager().createQuery(jpaQuery, Definition.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

    @Transactional
    public void Definition.persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

    @Transactional
    public void Definition.remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Definition attached = Definition.findDefinition(this.id);
            this.entityManager.remove(attached);
        }
    }

    @Transactional
    public void Definition.flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }

    @Transactional
    public void Definition.clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }

    @Transactional
    public Definition Definition.merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        Definition merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }

}


Working redirection to 503 - Now adding cflowbelow(thisAspect)

import net.winstone.core.WinstoneConstant;
import org.slf4j.LoggerFactory;

// Java EE servlet API
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

// Used to scope pointcuts
import net.winstone.core.listener.RequestHandlerThread;
import net.winstone.core.ServletConfiguration;
import net.winstone.core.SimpleRequestDispatcher;

// Rate Limiter
import edu.utwente.aop.tools.RateLimiter;
import java.util.concurrent.TimeUnit;

// exceptions from Servlet.service(..)
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

// We redirect the call flow to error servlet
import net.winstone.servlet.ErrorServlet;

/**
 * Ensure that the request is allowed by the RateLimiter before continuing..
 */
public privileged aspect RateLimitingAspect  percflow(processRequest()) {
    private enum State { NOTICKET, TICKET, NOTICKET_AVAILABLE };

    public final int RESPONSE_TIME_MS = 1000;

    /** public because it is implicitly accessed from WebAppConfiguration */
    public State state = State.NOTICKET;

    static org.slf4j.Logger logger = LoggerFactory.getLogger(Servlet.class);
    // Allow 5 requests per limit
    private static RateLimiter limits = new RateLimiter(5, 1, TimeUnit.MINUTES);

    /**
     * Pointcut that captures all requests flows in which a request is handled.
     * This is used to instantiate this aspect per request that is handled.
     */
    pointcut processRequest(): call(* processRequest(..)) && within(RequestHandlerThread);

    pointcut callServiceWithArgs(Servlet servlet, ServletRequest req, ServletResponse resp): call(void Servlet.service(..)) && target(servlet) && args(req, resp);

    pointcut inWinstoneServletConfiguration(): within(ServletConfiguration);

    pointcut handlingError(): cflow(call(void sendError(int, String)) && target(HttpServletResponse));

    /** Around did not work when trying to abstract call(...) && args into a seperate pointcut
     * @throws IOException when sendError throws an exception.
     */
    void around(ServletRequest req, ServletResponse resp) throws IOException: inWinstoneServletConfiguration() && !handlingError() && call(void Servlet.service(..)) && args(req, resp) {

        ensureTicket();

        if (state != State.TICKET) {
            // Instantiate new 503-UNAVAILABLE
            logger.info("Redirecting request to 503");
            ((HttpServletResponse) resp).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Rate limit reached - Throttled");
        } else {
            proceed(req, resp);
        }
    }

    /**
     * Try to get a ticket from the state machine
     */
    private void ensureTicket() {
        switch (state) {
            case TICKET:
                logger.info("Re-using ticket");
                break;
            case NOTICKET:
                logger.info("Trying to acquire ticket for " + this);
                if (limits.acquire(RESPONSE_TIME_MS)) {
                    logger.info("Acquired ticket");
                    state = State.TICKET;
                } else {
                    state = State.NOTICKET_AVAILABLE;
                }
                break;
            case NOTICKET_AVAILABLE:
                logger.info("No tickets available");
                break;
        }
    }
}

import net.winstone.core.WinstoneConstant;
import org.slf4j.LoggerFactory;

// Java EE servlet API
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

// Used to scope pointcuts
import net.winstone.core.listener.RequestHandlerThread;
import net.winstone.core.ServletConfiguration;
import net.winstone.core.SimpleRequestDispatcher;

// Rate Limiter
import edu.utwente.aop.tools.RateLimiter;
import java.util.concurrent.TimeUnit;

// exceptions from Servlet.service(..)
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

// We redirect the call flow to error servlet
import net.winstone.servlet.ErrorServlet;

/**
 * Ensure that the request is allowed by the RateLimiter before continuing..
 */
public aspect RateLimitingAspect  percflow(processRequest()) {
    private enum State { UNINITIALIZED, NOTICKET, TICKET, NOTICKET_AVAILABLE };

    public final int RESPONSE_TIME_MS = 1000;

    /** public because it is implicitly accessed from WebAppConfiguration */
    public State state = State.UNINITIALIZED;

    static org.slf4j.Logger logger = LoggerFactory.getLogger(Servlet.class);
    // Allow 5 requests per limit
    private static RateLimiter limits = new RateLimiter(5, 1, TimeUnit.MINUTES);

    pointcut processRequest(): call(* processRequest(..)) && within(RequestHandlerThread);

    pointcut servletCallService(Servlet servlet, ServletRequest req, ServletResponse resp): call(void Servlet.service(..)) && target(servlet) && args(req, resp);

    pointcut inWinstoneServletConfiguration(): within(ServletConfiguration);

    before(): processRequest() {
        logger.info("Processrequest!");
        state = State.NOTICKET;
    }

    // TODO: Rewrite to around and call service on different type.
    // TODO: Voor cflowbelow
    before(ServletRequest req, ServletResponse resp) throws ServletException, IOException: inWinstoneServletConfiguration() && call(void Servlet.service(..)) && args(req, resp) {
        logger.info(this.toString() + req + resp);

        getTicket();

        if (state != State.TICKET) {
            // Instantiate new 503-UNAVAILABLE
            ((HttpServletResponse) resp).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Rate limit reached - Throttled");

            // TODO: Should not continue the regular call on service.
        }
    }

    public void getTicket() {
        switch (state) {
            case TICKET:
                logger.info("Re-using ticket");
                break;
            case NOTICKET:
                logger.info("Trying to acquire ticket for " + this);
                if (limits.acquire(RESPONSE_TIME_MS)) {
                    logger.info("Acquired ticket");
                    state = State.TICKET;
                } else {
                    state = State.NOTICKET_AVAILABLE;
                }
                break;
            case NOTICKET_AVAILABLE:
                logger.info("No tickets available");
                break;
            case UNINITIALIZED: // ensure this does not happen
                throw new IllegalStateException("Should not receive request before init");
        }
    }
}


XWIKI-3503: Change Component Manager API to replace roles passed as Strings in favor of classes

* Fixed compatibility aspect that was wrong.

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

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

import com.xpn.xwiki.XWikiContext;

/**
 * Add a backward compatibility layer to the {@link Utils} class.
 *
 * @version $Id: UtilsCompatibilityAspect.aj 10166 2008-06-09 12:50:40Z sdumitriu $
 */
public privileged aspect UtilsCompatibilityAspect
{
    /**
     * Lookup a XWiki component by role and hint.
     *
     * @param role the class (aka role) that the component implements
     * @param hint a value to differentiate different component implementations for the same role
     * @return the component's instance
     */
	public static Object Utils.getComponent(String role, String hint)
    {
        try {
            return getComponent(Utils.class.getClassLoader().loadClass(role), hint);
        } catch (Exception e) {
            throw new RuntimeException("Failed to load component [" + role + "] for hint [" + hint + "]", e);
        }
    }

    /**
     * Lookup a XWiki component by role (uses the default hint).
     *
     * @param role the class (aka role) that the component implements
     * @return the component's instance
     */
    public static Object Utils.getComponent(String role)
    {
        return getComponent(role, "default");
    }
}

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

import com.xpn.xwiki.XWikiContext;

/**
 * Add a backward compatibility layer to the {@link Utils} class.
 *
 * @version $Id: UtilsCompatibilityAspect.aj 10166 2008-06-09 12:50:40Z sdumitriu $
 */
public privileged aspect UtilsCompatibilityAspect
{
    /**
     * Lookup a XWiki component by role and hint.
     *
     * @param role the class (aka role) that the component implements
     * @param hint a value to differentiate different component implementations for the same role
     * @return the component's instance
     */
	public static Object Utils.getComponent(String role, String hint)
    {
        try {
            return getComponent(Utils.class.getClassLoader().loadClass(role).getName(), hint);
        } catch (Exception e) {
            throw new RuntimeException("Failed to load component [" + role + "] for hint [" + hint + "]", e);
        }
    }

    /**
     * Lookup a XWiki component by role (uses the default hint).
     *
     * @param role the class (aka role) that the component implements
     * @return the component's instance
     */
    public static Object Utils.getComponent(String role)
    {
        return getComponent(role, "default");
    }
}