Make sure the single update request is aborted onPause()

/*
 * 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.AsyncTask;
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;
    private boolean waitForFixDialogShown = false;

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

        if (ignitedLastKnownLocationTask != null) {
            if (ignitedLastKnownLocationTask.getStatus() != AsyncTask.Status.FINISHED) {
                Log.d(LOG_TAG, "Cancel last location task");
                ignitedLastKnownLocationTask.cancel(true);
            }
            ignitedLastKnownLocationTask.getLastLocationFinder().cancel();
        }

        boolean finishing = activity.isFinishing();
        if (finishing) {
            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) {
            // TODO Migrate this to DialogFragment at some point
            if (showWaitForLocationDialog) {
                activity.showDialog(R.id.ign_loc_dialog_wait_for_fix);
                waitForFixDialogShown = true;
            }
            return;
        }

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, lng/acc): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude() + "/" + currentLocation.getAccuracy());
        // TODO Migrate this to DialogFragment at some point
        if (waitForFixDialogShown) {
            activity.removeDialog(R.id.ign_loc_dialog_wait_for_fix);
            waitForFixDialogShown = false;
        }
        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 == null || !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 != null && 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);
        }
    }

}

/*
 * 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;
    private boolean waitForFixDialogShown = false;

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

        if (ignitedLastKnownLocationTask != null) {
            ignitedLastKnownLocationTask.cancel(true);
        }

        boolean finishing = activity.isFinishing();
        if (finishing) {
            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) {
            // TODO Migrate this to DialogFragment at some point
            if (showWaitForLocationDialog) {
                activity.showDialog(R.id.ign_loc_dialog_wait_for_fix);
                waitForFixDialogShown = true;
            }
            return;
        }

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, lng/acc): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude() + "/" + currentLocation.getAccuracy());
        // TODO Migrate this to DialogFragment at some point
        if (waitForFixDialogShown) {
            activity.removeDialog(R.id.ign_loc_dialog_wait_for_fix);
            waitForFixDialogShown = false;
        }
        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 == null || !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 != null && 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);
        }
    }

}


add imports for Linked versions

add imports for Linked versions

/*
 * 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.LinkedHashMap;
import java.util.LinkedHashSet;
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 (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();
    }
}


System.exit(0) added in case of strong failure

package benchmark.competition.java.javaMOP.monitoring;

import java.util.concurrent.locks.Lock;

import monitoring.impl.MonitorFactory;
import monitoring.intf.Monitor;
import properties.Property;
import properties.competition.JavaMOP;
import structure.impl.other.Verdict;
import structure.intf.QEA;
import benchmark.competition.java.javaMOP.LockTest;

public aspect JavaMOPTwoAspect {

	private final Monitor monitor;

	private final int LOCK = 1;
	private final int UNLOCK = 2;

	public JavaMOPTwoAspect() {
		QEA qea = new JavaMOP().make(Property.JAVAMOP_TWO);
		monitor = MonitorFactory.create(qea);
	}

	pointcut lockPC(Thread thread, Lock lockObj) : call(void Lock.lock())
		&& target(lockObj) && this(thread);

	pointcut unlockPC(Thread thread, Lock lockObj) : call(void Lock.unlock())
		&& target(lockObj) && this(thread);

	before(Thread thread, Lock lockObj) : lockPC(thread, lockObj) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(LOCK, thread, lockObj);
		}
		if (verdict == Verdict.FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. [thread="
							+ thread
							+ ", lock="
							+ lockObj
							+ "]. A thread should release a lock as many times as it acquires the lock.");
			System.exit(0);
		}
	}

	before(Thread thread, Lock lockObj) : unlockPC(thread, lockObj) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(UNLOCK, thread, lockObj);
		}
		if (verdict == Verdict.FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. [thread="
							+ thread
							+ ", lock="
							+ lockObj
							+ "]. A thread should release a lock as many times as it acquires the lock.");
			System.exit(0);
		}
	}

	pointcut endOfProgram() : execution(void LockTest.main(String[]));

	after() : endOfProgram() {
		Verdict verdict = monitor.end();
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. A thread should release a lock as many times as it acquires the lock.");
		} else {
			System.err.println("Property JavaMOP 2 satisfied");
		}
	}
}

package benchmark.competition.java.javaMOP.monitoring;

import java.util.concurrent.locks.Lock;

import monitoring.impl.MonitorFactory;
import monitoring.intf.Monitor;
import properties.Property;
import properties.competition.JavaMOP;
import structure.impl.other.Verdict;
import structure.intf.QEA;
import benchmark.competition.java.javaMOP.LockTest;

public aspect JavaMOPTwoAspect {

	private final Monitor monitor;

	private final int LOCK = 1;
	private final int UNLOCK = 2;

	public JavaMOPTwoAspect() {
		QEA qea = new JavaMOP().make(Property.JAVAMOP_TWO);
		monitor = MonitorFactory.create(qea);
	}

	pointcut lockPC(Thread thread, Lock lockObj) : call(void Lock.lock())
		&& target(lockObj) && this(thread);

	pointcut unlockPC(Thread thread, Lock lockObj) : call(void Lock.unlock())
		&& target(lockObj) && this(thread);

	before(Thread thread, Lock lockObj) : lockPC(thread, lockObj) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(LOCK, thread, lockObj);
		}
		if (verdict == Verdict.FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. [thread="
							+ thread
							+ ", lock="
							+ lockObj
							+ "]. A thread should release a lock as many times as it acquires the lock.");
		}
	}

	before(Thread thread, Lock lockObj) : unlockPC(thread, lockObj) {
		Verdict verdict = null;
		synchronized (monitor) {
			verdict = monitor.step(UNLOCK, thread, lockObj);
		}
		if (verdict == Verdict.FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. [thread="
							+ thread
							+ ", lock="
							+ lockObj
							+ "]. A thread should release a lock as many times as it acquires the lock.");
		}
	}

	pointcut endOfProgram() : execution(void LockTest.main(String[]));

	after() : endOfProgram() {
		Verdict verdict = monitor.end();
		if (verdict == Verdict.FAILURE || verdict == Verdict.WEAK_FAILURE) {
			System.err
					.println("Violation in JavaMOP 2. A thread should release a lock as many times as it acquires the lock.");
		} else {
			System.err.println("Property JavaMOP 2 satisfied");
		}
	}
}


package rename

package rename

package org.slc.sli.common.util.performance;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slc.sli.util.threadutil.ThreadLocalStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Aspect for common performance measurements
 *
 * @author ifaybyshev
 *
 */
@Aspect
abstract public class PerformanceTrackingAspect {

	protected Logger performanceLog = LoggerFactory.getLogger("PerformanceLogger");

	protected Logger log = LoggerFactory.getLogger(PerformanceTrackingAspect.class);

	protected ThreadLocalStorage store = new ThreadLocalStorage(String.valueOf(System.currentTimeMillis()));

	// storing a field/value into the store
	@Pointcut("@annotation(org.slc.sli.util.performance.PutResultInContext)")
	public void putResultInContext() {
	}

	@AfterReturning(pointcut = "@annotation(returnName)", argNames = "returnName", returning = "returnValue")
	public void handleStoringReturnPointcut(String returnValue,
			PutResultInContext returnName) {
		log.info("StoreReturnPointcut -- Storing a field Into Performance Local Store: "
				+ returnName.returnName() + " = " + returnValue);
		store.put(returnName.returnName(), returnValue);
	}

	@Pointcut("@annotation(org.slc.sli.util.performance.Profiled)")
	public void profiled() {
	}

	@Around("profiled()")
	public Object handleProfiledAnnotation(ProceedingJoinPoint pjp)
			throws Throwable {
		long start = System.currentTimeMillis();

		Object output = pjp.proceed();

		this.profileMethod(pjp, start);

		return output;
	}

	public void profileMethod(ProceedingJoinPoint pjp, long start) {
		this.sendPerformanceMessage(pjp.getThis().getClass().getName() + "."
				+ pjp.getSignature().getName(), start, System.currentTimeMillis());
	}

	protected void sendPerformanceMessage(String callerName,
			long startTimestamp, long endTimestamp) {
		// send message to performance store
		performanceLog.info("<ingestionPerformance>" + "<caller>" + callerName
				+ "</caller>" + "<timing>" + "<startTimestamp>"
				+ startTimestamp + "</startTimestamp>" + "<endTimestamp>"
				+ endTimestamp + "</endTimestamp>" + "<elapsedMs>"
				+ (endTimestamp - startTimestamp) + "</elapsedMs>"
				+ "</timing>" + "</ingestionPerformance>");
	}

}

package org.slc.sli.util.performance;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slc.sli.util.threadutil.ThreadLocalStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Aspect for common performance measurements
 *
 * @author ifaybyshev
 *
 */
@Aspect
abstract public class PerformanceTrackingAspect {

	protected Logger performanceLog = LoggerFactory.getLogger("PerformanceLogger");

	protected Logger log = LoggerFactory.getLogger(PerformanceTrackingAspect.class);

	protected ThreadLocalStorage store = new ThreadLocalStorage(String.valueOf(System.currentTimeMillis()));

	// storing a field/value into the store
	@Pointcut("@annotation(org.slc.sli.util.performance.PutResultInContext)")
	public void putResultInContext() {
	}

	@AfterReturning(pointcut = "@annotation(returnName)", argNames = "returnName", returning = "returnValue")
	public void handleStoringReturnPointcut(String returnValue,
			PutResultInContext returnName) {
		log.info("StoreReturnPointcut -- Storing a field Into Performance Local Store: "
				+ returnName.returnName() + " = " + returnValue);
		store.put(returnName.returnName(), returnValue);
	}

	@Pointcut("@annotation(org.slc.sli.util.performance.Profiled)")
	public void profiled() {
	}

	@Around("profiled()")
	public Object handleProfiledAnnotation(ProceedingJoinPoint pjp)
			throws Throwable {
		long start = System.currentTimeMillis();

		Object output = pjp.proceed();

		this.profileMethod(pjp, start);

		return output;
	}

	public void profileMethod(ProceedingJoinPoint pjp, long start) {
		this.sendPerformanceMessage(pjp.getThis().getClass().getName() + "."
				+ pjp.getSignature().getName(), start, System.currentTimeMillis());
	}

	protected void sendPerformanceMessage(String callerName,
			long startTimestamp, long endTimestamp) {
		// send message to performance store
		performanceLog.info("<ingestionPerformance>" + "<caller>" + callerName
				+ "</caller>" + "<timing>" + "<startTimestamp>"
				+ startTimestamp + "</startTimestamp>" + "<endTimestamp>"
				+ endTimestamp + "</endTimestamp>" + "<elapsedMs>"
				+ (endTimestamp - startTimestamp) + "</elapsedMs>"
				+ "</timing>" + "</ingestionPerformance>");
	}

}


fixed bug in statistics calculation

fixed bug in statistics calculation

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

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

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

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

    private static GUI gui;

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

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

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

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

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

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

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

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

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

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

            int curPlayer = player.ordinal();

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

            // percentage of won games by gametype
            int soliCompleteAmount = data.getGamesPlayedPerType()[Games.SOLO.ordinal()]
                    + data.getGamesPlayedPerType()[Games.SIE.ordinal()]
                    + data.getGamesPlayedPerType()[Games.TOUT.ordinal()];
            int soliCompleteAmountWon = data.getGamesWonPerType()[Games.SOLO.ordinal()]
                    + data.getGamesWonPerType()[Games.SIE.ordinal()]
                    + data.getGamesWonPerType()[Games.TOUT.ordinal()];
            double soliGesamtWonPerc = (soliCompleteAmount > 0
                    ? (double) soliCompleteAmountWon / soliCompleteAmount
                    : 0.0) * 100;

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

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

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

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

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

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

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

        return plot;
    }

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

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

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

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

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

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

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

        return plot;
    }
}

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

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

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

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

    private static GUI gui;

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

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

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

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

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

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

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

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

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

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

            int curPlayer = player.ordinal();

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

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

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

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

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

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

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

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

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

        return plot;
    }

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

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

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

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

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

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

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

        return plot;
    }
}


commit 46c49b79ea575837e15bae84b034d54682cd158b
Author: Iyappan Srinivasan <iyappans@yahoo-inc.com>
Date:   Fri Jul 23 05:52:01 2010 +0000

    MAPREDUCE-1955 https://issues.apache.org/jira/secure/attachment/12450264/1955-ydist-security-patch.txt

git-svn-id: 7e7a2d564dde2945c3a26e08d1235fcc0cb7aba1@1077581 13f79535-47bb-0310-9956-ffa450edef68

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.mapred;

import java.io.IOException;
import org.apache.hadoop.mapreduce.test.system.JobInfo;

/**
 * Aspect to add a utility method in the JobInProgress for easing up the
 * construction of the JobInfo object.
 */
privileged aspect JobInProgressAspect {

  /**
   * Returns a read only view of the JobInProgress object which is used by the
   * client.
   *
   * @return JobInfo of the current JobInProgress object
   */
  public JobInfo JobInProgress.getJobInfo() {
    String historyLoc = getHistoryPath();
    JobInfoImpl jobInfoImpl;
    if (tasksInited) {
      jobInfoImpl = new JobInfoImpl(
          this.getJobID(), this.isSetupLaunched(), this.isSetupFinished(), this
              .isCleanupLaunched(), this.runningMaps(), this.runningReduces(),
          this.pendingMaps(), this.pendingReduces(), this.finishedMaps(), this
              .finishedReduces(), this.getStatus(), historyLoc, this
              .getBlackListedTrackers(), false, this.numMapTasks,
          this.numReduceTasks, this.isHistoryFileCopied());
    } else {
      jobInfoImpl = new JobInfoImpl(
          this.getJobID(), false, false, false, 0, 0, this.pendingMaps(), this
              .pendingReduces(), this.finishedMaps(), this.finishedReduces(),
          this.getStatus(), historyLoc, this.getBlackListedTrackers(), this
              .isComplete(), this.numMapTasks, this.numReduceTasks,
              this.isHistoryFileCopied());
    }
    jobInfoImpl.setFinishTime(getJobFinishTime());
    jobInfoImpl.setLaunchTime(getJobLaunchTime());
    jobInfoImpl.setNumSlotsPerReduce(getJobNumSlotsPerReduce());
    jobInfoImpl.setNumSlotsPerMap(getJobNumSlotsPerMap());
    return jobInfoImpl;
  }

  private long JobInProgress.getJobFinishTime() {
    long finishTime = 0;
    if (this.isComplete()) {
      finishTime = this.getFinishTime();
    }
    return finishTime;
  }

  private long JobInProgress.getJobLaunchTime() {
    long LaunchTime = 0;
    if (this.isComplete()) {
      LaunchTime = this.getLaunchTime();
    }
    return LaunchTime;
  }

  private int JobInProgress.getJobNumSlotsPerReduce() {
    int numSlotsPerReduce = 0;
    if (this.isComplete()) {
      numSlotsPerReduce = this.getNumSlotsPerReduce();
    }
    return numSlotsPerReduce;
  }

  private int JobInProgress.getJobNumSlotsPerMap() {
    int numSlotsPerMap = 0;
    if (this.isComplete()) {
      numSlotsPerMap = this.getNumSlotsPerMap();
    }
    return numSlotsPerMap;
 }

  private String JobInProgress.getHistoryPath() {
    String historyLoc = "";
    if(this.isComplete()) {
      historyLoc = this.getHistoryFile();
    } else {
      String historyFileName = null;
      try {
        historyFileName  = JobHistory.JobInfo.getJobHistoryFileName(conf,
            jobId);
      } catch(IOException e) {
      }
      if(historyFileName != null) {
        historyLoc = JobHistory.JobInfo.getJobHistoryLogLocation(
            historyFileName).toString();
      }
    }
    return historyLoc;
  }

}

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.mapred;

import java.io.IOException;
import org.apache.hadoop.mapreduce.test.system.JobInfo;

/**
 * Aspect to add a utility method in the JobInProgress for easing up the
 * construction of the JobInfo object.
 */
privileged aspect JobInProgressAspect {

  /**
   * Returns a read only view of the JobInProgress object which is used by the
   * client.
   *
   * @return JobInfo of the current JobInProgress object
   */
  public JobInfo JobInProgress.getJobInfo() {
    String historyLoc = getHistoryPath();
    JobInfoImpl jobInfoImpl;
    if (tasksInited.get()) {
      jobInfoImpl = new JobInfoImpl(
          this.getJobID(), this.isSetupLaunched(), this.isSetupFinished(), this
              .isCleanupLaunched(), this.runningMaps(), this.runningReduces(),
          this.pendingMaps(), this.pendingReduces(), this.finishedMaps(), this
              .finishedReduces(), this.getStatus(), historyLoc, this
              .getBlackListedTrackers(), false, this.numMapTasks,
          this.numReduceTasks, this.isHistoryFileCopied());
    } else {
      jobInfoImpl = new JobInfoImpl(
          this.getJobID(), false, false, false, 0, 0, this.pendingMaps(), this
              .pendingReduces(), this.finishedMaps(), this.finishedReduces(),
          this.getStatus(), historyLoc, this.getBlackListedTrackers(), this
              .isComplete(), this.numMapTasks, this.numReduceTasks,
              this.isHistoryFileCopied());
    }
    jobInfoImpl.setFinishTime(getJobFinishTime());
    jobInfoImpl.setLaunchTime(getJobLaunchTime());
    jobInfoImpl.setNumSlotsPerReduce(getJobNumSlotsPerReduce());
    jobInfoImpl.setNumSlotsPerMap(getJobNumSlotsPerMap());
    return jobInfoImpl;
  }

  private long JobInProgress.getJobFinishTime() {
    long finishTime = 0;
    if (this.isComplete()) {
      finishTime = this.getFinishTime();
    }
    return finishTime;
  }

  private long JobInProgress.getJobLaunchTime() {
    long LaunchTime = 0;
    if (this.isComplete()) {
      LaunchTime = this.getLaunchTime();
    }
    return LaunchTime;
  }

  private int JobInProgress.getJobNumSlotsPerReduce() {
    int numSlotsPerReduce = 0;
    if (this.isComplete()) {
      numSlotsPerReduce = this.getNumSlotsPerReduce();
    }
    return numSlotsPerReduce;
  }

  private int JobInProgress.getJobNumSlotsPerMap() {
    int numSlotsPerMap = 0;
    if (this.isComplete()) {
      numSlotsPerMap = this.getNumSlotsPerMap();
    }
    return numSlotsPerMap;
 }

  private String JobInProgress.getHistoryPath() {
    String historyLoc = "";
    if(this.isComplete()) {
      historyLoc = this.getHistoryFile();
    } else {
      String historyFileName = null;
      try {
        historyFileName  = JobHistory.JobInfo.getJobHistoryFileName(conf,
            jobId);
      } catch(IOException e) {
      }
      if(historyFileName != null) {
        historyLoc = JobHistory.JobInfo.getJobHistoryLogLocation(
            historyFileName).toString();
      }
    }
    return historyLoc;
  }

}


shorten logging to minor log levels

shorten logging to minor log levels

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

package de.cosmocode.palava.jpa.aspectj;

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

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

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

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

public final aspect EntityTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<EntityManager> currentManager;

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

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

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

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

        final Object returnValue;

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

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

        return returnValue;
    }

}

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

package de.cosmocode.palava.jpa.aspectj;

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

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

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

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

public final aspect EntityTransactionAspect extends AbstractPalavaAspect issingleton() {

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

    private Provider<EntityManager> currentManager;

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

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

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

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

        final Object returnValue;

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

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

        return returnValue;
    }

}