addressed other comments

addressed other comments

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        int samplingRate = getSampleRate(pathAndClass);

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

        // record the queue size
        this.counterInterface.recordGaugeValue("akka.queue.size", actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter("akka.actor.delivered", samplingRate, tags);
        this.counterInterface.incrementCounter("akka.actor.delivered." + msg.getClass().getSimpleName(), samplingRate, tags);

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

        // record the actor duration
        this.counterInterface.recordExecutionTime("akka.actor.duration", (int)duration, tags);

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

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

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

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

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

        this.numberOfActors.putIfAbsent(className, new AtomicLong(0));
        // increment and get the current number of actors of this type (if the value was 0, then this returns 1 -- which is correct)
        final long currentNumberOfActors = this.numberOfActors.get(className).incrementAndGet();

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

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

        this.numberOfActors.putIfAbsent(className, new AtomicLong(0));
        // decrement and get the current number of actors of this type (if the value was 1, then this returns 0 -- which is correct)
        final long currentNumberOfActors = this.numberOfActors.get(className).decrementAndGet();

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        int samplingRate = getSampleRate(pathAndClass);

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

        // record the queue size
        this.counterInterface.recordGaugeValue("akka.queue.size", actorCell.numberOfMessages(), tags);
        // record the message, general and specific
        this.counterInterface.incrementCounter("akka.actor.delivered", samplingRate, tags);
        this.counterInterface.incrementCounter("akka.actor.delivered." + msg.getClass().getSimpleName(), samplingRate, tags);

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

        // record the actor duration
        this.counterInterface.recordExecutionTime("akka.actor.duration", (int)duration, tags);

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

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

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

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

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

        this.numberOfActors.putIfAbsent(className, new AtomicLong(0));
        // increment and get the current number of actors of this type (if the value was 0, then this returns 1 -- which is correct)
        final long value = this.numberOfActors.get(className).incrementAndGet();

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

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

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

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

}


Widening the pointcut to catch more potential places where plugin-loading could be a problem.

git-svn-id: 2c527eb49caa05e19d6b2be874bf74fa9d7ea670@614330 13f79535-47bb-0310-9956-ffa450edef68

package org.apache.maven.errors;

import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
import org.apache.maven.plugin.PluginConfigurationException;
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.loader.PluginLoaderException;
import org.apache.maven.plugin.loader.PluginLoader;
import org.apache.maven.plugin.PluginExecutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.model.MojoBinding;
import org.apache.maven.lifecycle.statemgmt.StateManagementUtils;
import org.apache.maven.lifecycle.DefaultLifecycleExecutor;
import org.apache.maven.lifecycle.LifecycleException;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.plugin.DefaultPluginManager;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
import org.apache.maven.plugin.PluginParameterException;
import org.apache.maven.plugin.Mojo;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;

import java.util.List;

public privileged aspect LifecycleErrorReporterAspect
    extends AbstractCoreReporterAspect
{

    private pointcut le_executeGoalAndHandleFailures( MojoBinding binding ):
        execution( void DefaultLifecycleExecutor.executeGoalAndHandleFailures( MojoBinding, .. ) )
        && args( binding, .. );

    private pointcut le_executeGoalAndHandleFailures_withSession( MojoBinding binding, MavenSession session ):
        execution( void DefaultLifecycleExecutor.executeGoalAndHandleFailures( MojoBinding, MavenSession, .. ) )
        && args( binding, session, .. );

    private pointcut pm_executeMojo( MavenProject project ):
        execution( void PluginManager+.executeMojo( MavenProject, .. ) )
        && args( project, .. );

    private pointcut within_pm_executeMojo( MavenProject project ):
        withincode( void PluginManager+.executeMojo( MavenProject, .. ) )
        && args( project, .. );

    after( MojoBinding binding, MavenProject project ) throwing ( PluginLoaderException cause ):
        call( * PluginLoader+.loadPlugin( MojoBinding, MavenProject, .. ) )
        && args( binding, project, .. )
    {
        getReporter().reportErrorLoadingPlugin( binding, project, cause );
    }

    after( MojoBinding binding, MavenProject project ) throwing ( MojoExecutionException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && call( void Mojo+.execute() )
    {
        // this will be covered by the reportErrorLoadingPlugin(..) method.
        if ( !StateManagementUtils.RESOLVE_LATE_BOUND_PLUGIN_GOAL.equals( binding.getGoal() ) )
        {
            getReporter().reportMojoExecutionException( binding, project, cause );
        }
    }

    PluginExecutionException around( MojoBinding binding, MavenProject project ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && call( PluginExecutionException.new( .., String ) )
    {
        PluginExecutionException cause = proceed( binding, project );
        getReporter().reportInvalidPluginExecutionEnvironment( binding, project, cause );

        return cause;
    }

    after( MojoBinding binding, MavenProject project ) throwing ( ComponentLookupException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && withincode( Mojo DefaultPluginManager.getConfiguredMojo( .. ) )
        && call( Object PlexusContainer+.lookup( .. ) )
    {
        getReporter().reportMojoLookupError( binding, project, cause );
    }

    Parameter currentParameter;

    private pointcut paramGetName( Parameter parameter ):
        call( String Parameter.getName() )
        && target( parameter );

    private pointcut pm_validatePomConfig():
        execution( void DefaultPluginManager.validatePomConfiguration( .. ) );

    private pointcut within_pm_validatePomConfig():
        withincode( void DefaultPluginManager.validatePomConfiguration( .. ) );

    private pointcut pm_checkRequiredParameters():
        execution( void DefaultPluginManager.checkRequiredParameters( .. ) );

    private pointcut within_pm_checkRequiredParameters():
        withincode( void DefaultPluginManager.checkRequiredParameters( .. ) );

    before( Parameter parameter ):
        ( within_pm_validatePomConfig()
          || within_pm_checkRequiredParameters() )
        && paramGetName( parameter )
    {
        currentParameter = parameter;
    }

    after() returning:
        pm_validatePomConfig() ||
        pm_checkRequiredParameters()
    {
        currentParameter = null;
    }

    private pointcut pm_executeMojoWithSessionAndExec( MavenProject project, MojoExecution exec, MavenSession session, DefaultPluginManager manager ):
        execution( void DefaultPluginManager.executeMojo( MavenProject, MojoExecution, MavenSession ) )
        && args( project, exec, session )
        && this( manager );

    after( MojoBinding binding, MavenProject project, MojoExecution exec, MavenSession session, DefaultPluginManager manager ) throwing( PluginConfigurationException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojoWithSessionAndExec( project, exec, session, manager ) )
        && pm_validatePomConfig()
    {
        PathTranslator translator = manager.pathTranslator;
        Logger logger = new ConsoleLogger( Logger.LEVEL_INFO, "error reporting" );
        getReporter().reportAttemptToOverrideUneditableMojoParameter( currentParameter, binding, project, session, exec, translator, logger, cause );
    }

    PluginParameterException around( MojoBinding binding, MavenProject project, List invalidParameters ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && call( PluginParameterException.new( .., List ) )
        && args( .., invalidParameters )
    {
        PluginParameterException err = proceed( binding, project, invalidParameters );

        getReporter().reportMissingRequiredMojoParameter( binding, project, invalidParameters, err );

        return err;
    }

    private pointcut ppee_evaluate( String expression ):
        execution( Object PluginParameterExpressionEvaluator.evaluate( String ) )
        && args( expression );

    private pointcut within_ppee_evaluate( String expression ):
        withincode( Object PluginParameterExpressionEvaluator.evaluate( String ) )
        && args( expression );

    before( MojoBinding binding, MavenProject project, String expression, ExpressionEvaluationException err ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && cflow( ppee_evaluate( expression ) )
        && execution( ExpressionEvaluationException.new( String ) )
        && this( err )
    {
        getReporter().reportUseOfBannedMojoParameter( currentParameter,
                                                      binding,
                                                      project,
                                                      expression,
                                                      (String) PluginParameterExpressionEvaluator.BANNED_EXPRESSIONS.get( expression ),
                                                      err );
    }

    after( MojoBinding binding, MavenProject project, String expression ) throwing ( Exception cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && cflow( ppee_evaluate( expression ) )
        && within( PluginParameterExpressionEvaluator )
        && call( Object ReflectionValueExtractor.evaluate( String, Object ) )
    {
        getReporter().reportReflectionErrorWhileEvaluatingMojoParameter( currentParameter,
                                                      binding,
                                                      project,
                                                      expression,
                                                      cause );
    }

    after( MojoBinding binding, MavenProject project, PlexusConfiguration config ) throwing( PluginConfigurationException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && execution( void DefaultPluginManager.populatePluginFields( *, *, PlexusConfiguration, .. ) )
        && args( *, *, config, .. )
    {
        getReporter().reportErrorApplyingMojoConfiguration( binding, project, config, cause );
    }

    private pointcut pm_resolveTransitiveDependencies( MavenProject project, String scope ):
        execution( void DefaultPluginManager.resolveTransitiveDependencies( *, *, String, *, MavenProject ) )
        && args( *, *, scope, *, project );

    after( MavenProject project, String scope ) throwing( ArtifactNotFoundException cause ):
        pm_resolveTransitiveDependencies( project, scope )
    {
        getReporter().reportProjectDependenciesNotFound( project, scope, cause );
    }

    after( MavenProject project, String scope ) throwing( ArtifactResolutionException cause ):
        pm_resolveTransitiveDependencies( project, scope )
    {
        if ( cause instanceof MultipleArtifactsNotFoundException )
        {
            getReporter().reportProjectDependenciesNotFound( project, scope, (MultipleArtifactsNotFoundException) cause );
        }
        else
        {
            getReporter().reportProjectDependenciesUnresolvable( project, scope, cause );
        }
    }

    private pointcut le_getLifecycleBindings( List tasks, MavenProject configuringProject, String targetDescription ):
        execution( List DefaultLifecycleExecutor.getLifecycleBindings( List, MavenProject, *, String ) )
        && args( tasks, configuringProject, *, targetDescription );

    before( List tasks, MavenProject configuringProject, String targetDescription, LifecycleException cause ):
        cflow( le_getLifecycleBindings( tasks, configuringProject, targetDescription ) )
        && call( LifecycleExecutionException.new( .., LifecycleException ) )
        && args( .., cause )
    {
        getReporter().reportErrorFormulatingBuildPlan( tasks, configuringProject, targetDescription, cause );
    }

}

package org.apache.maven.errors;

import org.codehaus.plexus.logging.console.ConsoleLogger;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
import org.apache.maven.plugin.PluginConfigurationException;
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.loader.PluginLoaderException;
import org.apache.maven.plugin.loader.PluginLoader;
import org.apache.maven.plugin.PluginExecutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.model.MojoBinding;
import org.apache.maven.lifecycle.statemgmt.StateManagementUtils;
import org.apache.maven.lifecycle.DefaultLifecycleExecutor;
import org.apache.maven.lifecycle.LifecycleException;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.plugin.DefaultPluginManager;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
import org.apache.maven.plugin.PluginParameterException;
import org.apache.maven.plugin.Mojo;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;

import java.util.List;

public privileged aspect LifecycleErrorReporterAspect
    extends AbstractCoreReporterAspect
{

    private pointcut le_executeGoalAndHandleFailures( MojoBinding binding ):
        execution( void DefaultLifecycleExecutor.executeGoalAndHandleFailures( MojoBinding, .. ) )
        && args( binding, .. );

    private pointcut le_executeGoalAndHandleFailures_withSession( MojoBinding binding, MavenSession session ):
        execution( void DefaultLifecycleExecutor.executeGoalAndHandleFailures( MojoBinding, MavenSession, .. ) )
        && args( binding, session, .. );

    private pointcut pm_executeMojo( MavenProject project ):
        execution( void PluginManager+.executeMojo( MavenProject, .. ) )
        && args( project, .. );

    private pointcut within_pm_executeMojo( MavenProject project ):
        withincode( void PluginManager+.executeMojo( MavenProject, .. ) )
        && args( project, .. );

    after( MojoBinding binding, MavenProject project ) throwing ( PluginLoaderException cause ):
        cflow( le_executeGoalAndHandleFailures( MojoBinding ) )
        && call( * PluginLoader+.loadPlugin( MojoBinding, MavenProject, .. ) )
        && args( binding, project, .. )
    {
        getReporter().reportErrorLoadingPlugin( binding, project, cause );
    }

    after( MojoBinding binding, MavenProject project ) throwing ( MojoExecutionException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && call( void Mojo+.execute() )
    {
        // this will be covered by the reportErrorLoadingPlugin(..) method.
        if ( !StateManagementUtils.RESOLVE_LATE_BOUND_PLUGIN_GOAL.equals( binding.getGoal() ) )
        {
            getReporter().reportMojoExecutionException( binding, project, cause );
        }
    }

    PluginExecutionException around( MojoBinding binding, MavenProject project ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && call( PluginExecutionException.new( .., String ) )
    {
        PluginExecutionException cause = proceed( binding, project );
        getReporter().reportInvalidPluginExecutionEnvironment( binding, project, cause );

        return cause;
    }

    after( MojoBinding binding, MavenProject project ) throwing ( ComponentLookupException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && withincode( Mojo DefaultPluginManager.getConfiguredMojo( .. ) )
        && call( Object PlexusContainer+.lookup( .. ) )
    {
        getReporter().reportMojoLookupError( binding, project, cause );
    }

    Parameter currentParameter;

    private pointcut paramGetName( Parameter parameter ):
        call( String Parameter.getName() )
        && target( parameter );

    private pointcut pm_validatePomConfig():
        execution( void DefaultPluginManager.validatePomConfiguration( .. ) );

    private pointcut within_pm_validatePomConfig():
        withincode( void DefaultPluginManager.validatePomConfiguration( .. ) );

    private pointcut pm_checkRequiredParameters():
        execution( void DefaultPluginManager.checkRequiredParameters( .. ) );

    private pointcut within_pm_checkRequiredParameters():
        withincode( void DefaultPluginManager.checkRequiredParameters( .. ) );

    before( Parameter parameter ):
        ( within_pm_validatePomConfig()
          || within_pm_checkRequiredParameters() )
        && paramGetName( parameter )
    {
        currentParameter = parameter;
    }

    after() returning:
        pm_validatePomConfig() ||
        pm_checkRequiredParameters()
    {
        currentParameter = null;
    }

    private pointcut pm_executeMojoWithSessionAndExec( MavenProject project, MojoExecution exec, MavenSession session, DefaultPluginManager manager ):
        execution( void DefaultPluginManager.executeMojo( MavenProject, MojoExecution, MavenSession ) )
        && args( project, exec, session )
        && this( manager );

    after( MojoBinding binding, MavenProject project, MojoExecution exec, MavenSession session, DefaultPluginManager manager ) throwing( PluginConfigurationException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojoWithSessionAndExec( project, exec, session, manager ) )
        && pm_validatePomConfig()
    {
        PathTranslator translator = manager.pathTranslator;
        Logger logger = new ConsoleLogger( Logger.LEVEL_INFO, "error reporting" );
        getReporter().reportAttemptToOverrideUneditableMojoParameter( currentParameter, binding, project, session, exec, translator, logger, cause );
    }

    PluginParameterException around( MojoBinding binding, MavenProject project, List invalidParameters ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && call( PluginParameterException.new( .., List ) )
        && args( .., invalidParameters )
    {
        PluginParameterException err = proceed( binding, project, invalidParameters );

        getReporter().reportMissingRequiredMojoParameter( binding, project, invalidParameters, err );

        return err;
    }

    private pointcut ppee_evaluate( String expression ):
        execution( Object PluginParameterExpressionEvaluator.evaluate( String ) )
        && args( expression );

    private pointcut within_ppee_evaluate( String expression ):
        withincode( Object PluginParameterExpressionEvaluator.evaluate( String ) )
        && args( expression );

    before( MojoBinding binding, MavenProject project, String expression, ExpressionEvaluationException err ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && cflow( ppee_evaluate( expression ) )
        && execution( ExpressionEvaluationException.new( String ) )
        && this( err )
    {
        getReporter().reportUseOfBannedMojoParameter( currentParameter,
                                                      binding,
                                                      project,
                                                      expression,
                                                      (String) PluginParameterExpressionEvaluator.BANNED_EXPRESSIONS.get( expression ),
                                                      err );
    }

    after( MojoBinding binding, MavenProject project, String expression ) throwing ( Exception cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && cflow( pm_checkRequiredParameters() )
        && cflow( ppee_evaluate( expression ) )
        && within( PluginParameterExpressionEvaluator )
        && call( Object ReflectionValueExtractor.evaluate( String, Object ) )
    {
        getReporter().reportReflectionErrorWhileEvaluatingMojoParameter( currentParameter,
                                                      binding,
                                                      project,
                                                      expression,
                                                      cause );
    }

    after( MojoBinding binding, MavenProject project, PlexusConfiguration config ) throwing( PluginConfigurationException cause ):
        cflow( le_executeGoalAndHandleFailures( binding ) )
        && cflow( pm_executeMojo( project ) )
        && execution( void DefaultPluginManager.populatePluginFields( *, *, PlexusConfiguration, .. ) )
        && args( *, *, config, .. )
    {
        getReporter().reportErrorApplyingMojoConfiguration( binding, project, config, cause );
    }

    private pointcut pm_resolveTransitiveDependencies( MavenProject project, String scope ):
        execution( void DefaultPluginManager.resolveTransitiveDependencies( *, *, String, *, MavenProject ) )
        && args( *, *, scope, *, project );

    after( MavenProject project, String scope ) throwing( ArtifactNotFoundException cause ):
        pm_resolveTransitiveDependencies( project, scope )
    {
        getReporter().reportProjectDependenciesNotFound( project, scope, cause );
    }

    after( MavenProject project, String scope ) throwing( ArtifactResolutionException cause ):
        pm_resolveTransitiveDependencies( project, scope )
    {
        if ( cause instanceof MultipleArtifactsNotFoundException )
        {
            getReporter().reportProjectDependenciesNotFound( project, scope, (MultipleArtifactsNotFoundException) cause );
        }
        else
        {
            getReporter().reportProjectDependenciesUnresolvable( project, scope, cause );
        }
    }

    private pointcut le_getLifecycleBindings( List tasks, MavenProject configuringProject, String targetDescription ):
        execution( List DefaultLifecycleExecutor.getLifecycleBindings( List, MavenProject, *, String ) )
        && args( tasks, configuringProject, *, targetDescription );

    before( List tasks, MavenProject configuringProject, String targetDescription, LifecycleException cause ):
        cflow( le_getLifecycleBindings( tasks, configuringProject, targetDescription ) )
        && call( LifecycleExecutionException.new( .., LifecycleException ) )
        && args( .., cause )
    {
        getReporter().reportErrorFormulatingBuildPlan( tasks, configuringProject, targetDescription, cause );
    }

}


Fixed broken aspect after last location finder refactoring

/*
 * 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 AsyncTask<Void, Void, Location> ignitedLastKnownLocationTask;
    private SharedPreferences prefs;
    private Handler handler;

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

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

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

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

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

    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_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.minBatteryLevel());
        editor.putLong(IgnitedLocationConstants.SP_KEY_WAIT_FOR_GPS_FIX_INTERVAL,
                locationAnnotation.waitForGpsFix());
        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);

        boolean finishing = activity.isFinishing();
        if (finishing) {
            if (ignitedLastKnownLocationTask != null && ignitedLastKnownLocationTask.getStatus() != AsyncTask.Status.FINISHED) {
                ignitedLastKnownLocationTask.cancel(true);
            } else {
                PlatformSpecificImplementationFactory.getLastLocationFinder(context).cancel();
            }

            context = null;
        }
    }

    // after() : execution(* Activity.onDestroy(..)) && @this(IgnitedLocationActivity)
    // && within(@IgnitedLocationActivity *) {
    // }

    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, long): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude());
    }

    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 && showWaitForLocationDialog) {
            activity.showDialog(R.id.ign_loc_dialog_wait_for_fix);
            return;
        }

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, long): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude());
        boolean keepRequestingLocationUpdates = ((OnIgnitedLocationChangedListener) context)
                .onIgnitedLocationChanged(currentLocation);
        Bundle extras = freshLocation.getExtras();
        if (!keepRequestingLocationUpdates) {
            disableLocationUpdates(true);
            PlatformSpecificImplementationFactory.getLastLocationFinder(context).cancel();
            return;
        } else if (requestLocationUpdates
                && !extras.containsKey(ILastLocationFinder.LAST_LOCATION_TOO_OLD_EXTRA)) {
            // If we requested location updates, turn them on here.
            requestLocationUpdates(context);
        }

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

    /**
     * Start listening for location updates.
     */
    protected void requestLocationUpdates(Context context) {
        if (!locationUpdatesDisabled) {
            return;
        }
        Criteria locationUpdateCriteria;
        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);
        }
    }

}

/*
 * 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.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 AsyncTask<Void, Void, Location> ignitedLastKnownLocationTask;
    private SharedPreferences prefs;
    private Handler handler;

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

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

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

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

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

    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_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.minBatteryLevel());
        editor.putLong(IgnitedLocationConstants.SP_KEY_WAIT_FOR_GPS_FIX_INTERVAL,
                locationAnnotation.waitForGpsFix());
        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);

        boolean finishing = activity.isFinishing();
        if (finishing) {
            if (ignitedLastKnownLocationTask != null && ignitedLastKnownLocationTask.getStatus() != AsyncTask.Status.FINISHED) {
                ignitedLastKnownLocationTask.cancel(true);
            } else {
                PlatformSpecificImplementationFactory.getLastLocationFinder(context).cancel();
            }

            context = null;
        }
    }

    // after() : execution(* Activity.onDestroy(..)) && @this(IgnitedLocationActivity)
    // && within(@IgnitedLocationActivity *) {
    // }

    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, long): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude());
    }

    void around(Location freshLocation) : set(@IgnitedLocation Location *) && args(freshLocation)
        && (within(IgnitedLocationChangedReceiver) || within(com.github.ignition.location.utils.*)
                || 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 && showWaitForLocationDialog) {
            activity.showDialog(R.id.ign_loc_dialog_wait_for_fix);
            return;
        }

        currentLocation = freshLocation;
        Log.d(LOG_TAG, "New location from " + currentLocation.getProvider() + " (lat, long): "
                + currentLocation.getLatitude() + ", " + currentLocation.getLongitude());
        boolean keepRequestingLocationUpdates = ((OnIgnitedLocationChangedListener) context)
                .onIgnitedLocationChanged(currentLocation);
        Bundle extras = freshLocation.getExtras();
        if (!keepRequestingLocationUpdates) {
            disableLocationUpdates(true);
            PlatformSpecificImplementationFactory.getLastLocationFinder(context).cancel();
            return;
        } else if (requestLocationUpdates
                && !extras.containsKey(ILastLocationFinder.LAST_LOCATION_TOO_OLD_EXTRA)) {
            // If we requested location updates, turn them on here.
            requestLocationUpdates(context);
        }

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

    /**
     * Start listening for location updates.
     */
    protected void requestLocationUpdates(Context context) {
        if (!locationUpdatesDisabled) {
            return;
        }
        Criteria locationUpdateCriteria;
        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);
        }
    }

}


log plus beau/propre

log plus beau/propre

package logger;

import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import ca.ulaval.ticketmaster.events.tickets.model.Ticket;
import ca.ulaval.ticketmaster.users.model.User;

public aspect LogBoughtTicketAspect {

	private static final String LOG_FILE = "src/main/resources/log.log";
	private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
	private static void log( String str )
	{
		FileWriter fwLog = null;

		try {
			fwLog = new FileWriter(LOG_FILE, true);
			fwLog.append("\n");
			fwLog.append(dateFormat.format(new Date()));
			fwLog.append(" :\n");
			fwLog.append(str);
			fwLog.flush();
			fwLog.close();
		} catch (IOException e) {
			System.out.println("Ne peut pas logger :");
			e.printStackTrace();
		}

	}

	pointcut logConfirmation() :
		execution(
				private void ca.ulaval.ticketmaster.dao.util.DataManager.sendConfirmationMail(User, UUID, List<Ticket>) );

	@SuppressWarnings("unchecked")
	before() : logConfirmation()
	{
		System.out.println("around");

		User user = (User)thisJoinPoint.getArgs()[0];
		UUID transactionId = (UUID)thisJoinPoint.getArgs()[1];
		ArrayList<Ticket> ticketList = (ArrayList<Ticket>)thisJoinPoint.getArgs()[2];

		LogBoughtTicketAspect.log("Envoi du courriel de confirmation  l'utilisateur '" + user.getUsername()
				+ "' (email='" + user.getEmail() + "') avec transactionId = '" + transactionId
				+ "', les billets :\n" + Arrays.toString(ticketList.toArray()));
	}

}

package logger;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import ca.ulaval.ticketmaster.events.tickets.model.Ticket;
import ca.ulaval.ticketmaster.purchase.model.PurchaseViewModel;
import ca.ulaval.ticketmaster.users.model.User;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;

public aspect LogBoughtTicketAspect {

	private static final String LOG_FILE = "src/main/resources/log.log";
	private static void log( String str )
	{
		FileWriter fwLog = null;

		try {
			fwLog = new FileWriter(LOG_FILE, true);
			fwLog.append(str);
			fwLog.flush();
			fwLog.close();
		} catch (IOException e) {
			System.out.println("Ne peut pas logger :");
			e.printStackTrace();
		}

	}

	//Purchase
	pointcut logPurchase() :
		execution(
				public String ca.ulaval.ticketmaster.purchase.PurchaseController.purchase(PurchaseViewModel, Model, HttpSession,
					    BindingResult, HttpServletRequest) );

	before() : logPurchase()
	{
		System.out.println("About to log");

		System.out.println(thisJoinPoint.getSignature());
		System.out.println(thisJoinPoint.getArgs().length);

		System.out.println(thisJoinPoint.getArgs()[0] instanceof PurchaseViewModel);

		if ( thisJoinPoint.getArgs()[0] instanceof PurchaseViewModel )
		{
			PurchaseViewModel pModel = (PurchaseViewModel)thisJoinPoint.getArgs()[0];

			System.out.println(pModel.toString());
		}
		//pModel.
		//System.out.println(model.);
				//thisJoinPoint().getArgs();
	}

	pointcut logConfirmation() :
		execution(
				private void ca.ulaval.ticketmaster.dao.util.DataManager.sendConfirmationMail(User, UUID, List<Ticket>) );

	@SuppressWarnings("unchecked")
	Object around() : logConfirmation()
	{
		System.out.println("around");

		User user = (User)thisJoinPoint.getArgs()[0];
		UUID transactionId = (UUID)thisJoinPoint.getArgs()[1];
		ArrayList<Ticket> ticketList = (ArrayList<Ticket>)thisJoinPoint.getArgs()[2];

		LogBoughtTicketAspect.log("Envoi du courriel de confirmation  l'utilisateur '" + user.getUsername()
				+ "' avec transactionId = '" + transactionId
				+ "', les billets :\n" + Arrays.toString(ticketList.toArray()));

		Object retval = proceed();

		return retval;
	}

}