//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.server.handler;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;

A collection of handlers.

The default implementations calls all handlers in list order, regardless of the response status or exceptions. Derived implementation may alter the order or the conditions of calling the contained handlers.

/** * A collection of handlers. * <p> * The default implementations calls all handlers in list order, * regardless of the response status or exceptions. Derived implementation * may alter the order or the conditions of calling the contained * handlers. */
@ManagedObject("Handler of multiple handlers") public class HandlerCollection extends AbstractHandlerContainer { private final boolean _mutableWhenRunning; protected final AtomicReference<Handlers> _handlers = new AtomicReference<>(); public HandlerCollection() { this(false); } public HandlerCollection(Handler... handlers) { this(false, handlers); } public HandlerCollection(boolean mutableWhenRunning, Handler... handlers) { _mutableWhenRunning = mutableWhenRunning; if (handlers.length > 0) setHandlers(handlers); }
Returns:the array of handlers.
/** * @return the array of handlers. */
@Override @ManagedAttribute(value = "Wrapped handlers", readonly = true) public Handler[] getHandlers() { Handlers handlers = _handlers.get(); return handlers == null ? null : handlers._handlers; }
Params:
  • handlers – the array of handlers to set.
/** * @param handlers the array of handlers to set. */
public void setHandlers(Handler[] handlers) { if (!_mutableWhenRunning && isStarted()) throw new IllegalStateException(getState()); while (true) { if (updateHandlers(_handlers.get(), newHandlers(handlers))) break; } } protected Handlers newHandlers(Handler[] handlers) { if (handlers == null || handlers.length == 0) return null; return new Handlers(handlers); } protected boolean updateHandlers(Handlers old, Handlers handlers) { if (handlers != null) { // check for loops for (Handler handler : handlers._handlers) { if (handler == this || (handler instanceof HandlerContainer && Arrays.asList(((HandlerContainer)handler).getChildHandlers()).contains(this))) throw new IllegalStateException("setHandler loop"); } // Set server for (Handler handler : handlers._handlers) { if (handler.getServer() != getServer()) handler.setServer(getServer()); } } if (_handlers.compareAndSet(old, handlers)) { Handler[] oldBeans = old == null ? null : old._handlers; Handler[] newBeans = handlers == null ? null : handlers._handlers; updateBeans(oldBeans, newBeans); return true; } return false; } @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (isStarted()) { Handlers handlers = _handlers.get(); if (handlers == null) return; MultiException mex = null; for (Handler handler : handlers._handlers) { try { handler.handle(target, baseRequest, request, response); } catch (IOException | RuntimeException e) { throw e; } catch (Exception e) { if (mex == null) mex = new MultiException(); mex.add(e); } } if (mex != null) { if (mex.size() == 1) throw new ServletException(mex.getThrowable(0)); else throw new ServletException(mex); } } }
Adds a handler. This implementation adds the passed handler to the end of the existing collection of handlers. If the handler is already added, it is removed and readded
/** * Adds a handler. * This implementation adds the passed handler to the end of the existing collection of handlers. * If the handler is already added, it is removed and readded */
public void addHandler(Handler handler) { while (true) { Handlers old = _handlers.get(); Handlers handlers = newHandlers(ArrayUtil.addToArray(old == null ? null : ArrayUtil.removeFromArray(old._handlers, handler), handler, Handler.class)); if (updateHandlers(old, handlers)) break; } }
Prepends a handler. This implementation adds the passed handler to the start of the existing collection of handlers.
/** * Prepends a handler. * This implementation adds the passed handler to the start of the existing collection of handlers. */
public void prependHandler(Handler handler) { while (true) { Handlers old = _handlers.get(); Handlers handlers = newHandlers(ArrayUtil.prependToArray(handler, old == null ? null : old._handlers, Handler.class)); if (updateHandlers(old, handlers)) break; } } public void removeHandler(Handler handler) { while (true) { Handlers old = _handlers.get(); if (old == null || old._handlers.length == 0) break; Handlers handlers = newHandlers(ArrayUtil.removeFromArray(old._handlers, handler)); if (updateHandlers(old, handlers)) break; } } @Override protected void expandChildren(List<Handler> list, Class<?> byClass) { Handler[] handlers = getHandlers(); if (handlers != null) for (Handler h : handlers) { expandHandler(h, list, byClass); } } @Override public void destroy() { if (!isStopped()) throw new IllegalStateException("!STOPPED"); Handler[] children = getChildHandlers(); setHandlers(null); for (Handler child : children) { child.destroy(); } super.destroy(); } protected static class Handlers { private final Handler[] _handlers; protected Handlers(Handler[] handlers) { this._handlers = handlers; } public Handler[] getHandlers() { return _handlers; } } }