/* Copyright 2007 Alin Dreghiciu.
 *
 * 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.ops4j.pax.web.service.jetty.internal;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.ops4j.lang.NullArgumentException;
import org.ops4j.pax.web.service.spi.model.ContextModel;
import org.ops4j.pax.web.service.spi.model.ServerModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Jetty Handler collection that calls only the handler (=context) that matches
 * the request path after performing the substring based matching of requests
 * path to registered aliases.
 *
 * @author Alin Dreghiciu
 * @since 0.2.3, December 22, 2007
 */
class JettyServerHandlerCollection extends HandlerCollection {

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

	private final ServerModel serverModel;

	JettyServerHandlerCollection(final ServerModel serverModel) {
		super(true);
		NullArgumentException.validateNotNull(serverModel, "Server model");
		this.serverModel = serverModel;
	}

	@Override
	public void handle(final String target, final Request baseRequest,
					   final HttpServletRequest request, final HttpServletResponse response)
			throws IOException, ServletException {
		if (!isStarted()) {
			return;
		}

		final ContextModel matched = serverModel.matchPathToContext(target);
		if (matched != null) {
			// check for nulls and start complaining
			NullArgumentException.validateNotNull(matched.getHttpContext(),
					"The http Context of " + matched.getContextName()
							+ " is null");
			NullArgumentException.validateNotNull(getServer(),
					"The server is null!");

			final ContextHandler context = ((JettyServerWrapper) getServer())
					.getContext(matched.getHttpContext());

			try {
				NullArgumentException.validateNotNull(context,
						"Context (handler) for " + target);
				context.handle(target, baseRequest, request, response);

				//CHECKSTYLE:OFF
			} catch (EofException e) {
				throw e;
			} catch (RuntimeException e) {
				throw e;
			} catch (Exception e) {
				throw new ServletException(e);
			}
			//CHECKSTYLE:ON

		}
		// now handle all other handlers
		for (Handler handler : getHandlers()) {
			if (matched != null
					&& matchedContextEqualsHandler(matched, handler)) {
				continue;
			}
			handler.handle(target, baseRequest, request, response);
		}
	}

	private boolean matchedContextEqualsHandler(ContextModel matched,
												Handler handler) {
		return handler == ((JettyServerWrapper) getServer())
				.getContext(matched.getHttpContext());
	}

	@Override
	public boolean addBean(Object o) {
		LOG.debug("Adding bean: {}", o);

		if (!(o instanceof HttpServiceContext)) {
			LOG.debug("calling supper add bean ...");
			return super.addBean(o);
		}

		return addBean(o, false);
	}

}

@@ -3031,16 +3031,483 @@
 andlers%0A
+%09%09// PAXWEB-981 - let's ensure that only one org.eclipse.jetty.server.handler.ContextHandler can handle a request%0A%09%09// Servlets 3.1, 12.1 %22Use of URL Paths%22:%0A%09%09//  - Upon receipt of a client request, the Web container determines the Web application to which to forward it.%0A%09%09//  - The Web container next must locate the servlet to process the request using the path mapping procedure %5B...%5D%0A%09%09//  - The first successful match is used with no further matches attempted%0A
 %09%09for (H
@@ -3570,16 +3570,54 @@
 %0A%09%09%09%09%09&&
+ (handler instanceof ContextHandler %7C%7C
  matched
@@ -3655,16 +3655,17 @@
 andler))
+)
  %7B%0A%09%09%09%09c

Fix ASYNC servlet handling by skipping non-matched other ContextHandlers