/*
 * 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.wicket.request.cycle;

import org.apache.wicket.Application;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Url;

/**
 * A callback interface for various methods in the request cycle. If you are creating a framework
 * that needs to do something in this methods, rather than extending RequestCycle or one of its
 * subclasses, you should implement this callback and allow users to add your listener to their
 * custom request cycle.
 * <p>
 * These listeners can be added directly to the request cycle when it is created or to the
 * {@link Application}.
 * <p>
 * <b>NOTE</b>: a listener implementation is a singleton and hence needs to ensure proper handling
 * of multi-threading issues.
 * <p>
 * <h3>Call order</h3>
 * <p>
 * The interface methods are ordered in the execution order as Wicket goes through the request
 * cycle:
 * </p>
 * <ol>
 * <li>{@link #onBeginRequest(RequestCycle)}</li>
 * <li>{@link #onEndRequest(RequestCycle)}</li>
 * <li>{@link #onDetach(RequestCycle)}</li>
 * </ol>
 * <p>
 * The previous call sequence is valid for any Wicket request passing through the Wicket filter.
 * Additionally when a request handler was resolved, a new handler scheduled, or an unhandled
 * exception occurred during the request processing, any of the following can be called:
 * </p>
 * <ul>
 * <li>{@link #onRequestHandlerResolved(RequestCycle, org.apache.wicket.request.IRequestHandler)}</li>
 * <li>{@link #onRequestHandlerScheduled(RequestCycle, org.apache.wicket.request.IRequestHandler)}</li>
 * <li>{@link #onException(RequestCycle, Exception)}, followed by
 * {@link #onExceptionRequestHandlerResolved(RequestCycle, org.apache.wicket.request.IRequestHandler, Exception)} </li>
 * </ul>
 * 
 * <h3>Implementing your own</h3>
 * <p>
 * Use {@link AbstractRequestCycleListener} for a default, empty implementation as a base class.
 * </p>
 * 
 * <h3>Example</h3>
 * <p>
 * A short example of a request counter.
 * </p>
 * 
 * <pre>
 * public class RequestCounter extends AbstractRequestCycleListener
 * {
 * 	private AtomicLong counter = new AtomicLong(0);
 * 
 * 	public void onBeginRequest(RequestCycle cycle)
 * 	{
 * 		counter.incrementAndGet();
 * 	}
 * 
 * 	public long getRequestCount()
 * 	{
 * 		return counter.longValue();
 * 	}
 * }
 * 
 * public class MyApplication extends WebApplication
 * {
 * 	public void init()
 * 	{
 * 		super.init();
 * 		getRequestCycleListeners().add(new RequestCounter());
 * 	}
 * }
 * </pre>
 * 
 * @author Jeremy Thomerson
 * @author Martijn Dashorst
 * 
 * @see AbstractRequestCycleListener
 * @see org.apache.wicket.Application#getRequestCycleListeners()
 */
public interface IRequestCycleListener
{
	/**
	 * Called when the request cycle object is beginning its response
	 * 
	 * @param cycle
	 */
	default void onBeginRequest(RequestCycle cycle)
	{}

	/**
	 * Called when the request cycle object has finished before flushing the response
	 * 
	 * @param cycle
	 */
	default void onEndRequest(RequestCycle cycle)
	{}

	/**
	 * Called after the request cycle has been detached
	 * 
	 * @param cycle
	 */
	default void onDetach(RequestCycle cycle)
	{}

	/**
	 * Called when an {@link IRequestHandler} is resolved and will be executed.
	 * 
	 * @param cycle
	 * 
	 * @param handler
	 */
	default void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler)
	{}

	/**
	 * Called when a {@link IRequestHandler} has been scheduled. Can be called multiple times during
	 * a request when new handlers get scheduled for processing.
	 * 
	 * @param cycle
	 * @param handler
	 * @see RequestCycle#scheduleRequestHandlerAfterCurrent(IRequestHandler)
	 */
	default void onRequestHandlerScheduled(RequestCycle cycle, IRequestHandler handler)
	{}

	/**
	 * Called when there is an exception in the request cycle that would normally be handled by
	 * {@link RequestCycle#handleException(Exception)}
	 * 
	 * Note that in the event of an exception, {@link #onEndRequest(RequestCycle)} will still be called after
	 * these listeners have {@link #onException(RequestCycle, Exception)} called
	 * <p>
	 * <strong>Important</strong>: Custom implementations are recommended to <strong>not</strong> try to
	 * handle exceptions implementing {@link org.apache.wicket.IWicketInternalException} interface.
	 * Usually such kind of exceptions should be handled by the framework.
	 * </p>
	 *
	 * @param cycle The current {@link RequestCycle request cycle}
	 * @param ex
	 *            the exception that was passed in to
	 *            {@link RequestCycle#handleException(Exception)}
	 * @return request handler that will be executed or {@code null} if none. If a request handler
	 *         is returned, it will override any configured
	 *         {@link Application#getExceptionMapperProvider() exception mapper}.
	 */
	default IRequestHandler onException(RequestCycle cycle, Exception ex)
	{
		return null;
	}

	/**
	 * Called when an {@link IRequestHandler} is resolved for an exception and will be executed.
	 * 
	 * @param cycle
	 * @param handler
	 * @param exception
	 */
	default void onExceptionRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler,
		Exception exception)
	{}

	/**
	 * Called after an {@link IRequestHandler} has been executed. If the execution resulted in an
	 * exception this method will not be called for that particular {@link IRequestHandler}.
	 * 
	 * @param cycle
	 * @param handler
	 */
	default void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler)
	{}

	/**
	 * Called after a Url is generated for a {@link IRequestHandler}. This method can be used to
	 * modify generated urls, for example query parameters can be added.
	 * 
	 * @param cycle
	 * @param handler
	 * @param url
	 */
	default void onUrlMapped(RequestCycle cycle, IRequestHandler handler, Url url)
	{}
}
