All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.v3.services.impl.GrizzlyService Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2007-2017 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 * Portions Copyright [2018-2021] [Payara Foundation and/or its affiliates]
 */

package com.sun.enterprise.v3.services.impl;

import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.HttpService;
import com.sun.enterprise.config.serverbeans.MonitoringService;
import com.sun.enterprise.config.serverbeans.SystemProperty;
import com.sun.enterprise.config.serverbeans.VirtualServer;
import com.sun.enterprise.util.Result;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.v3.services.impl.monitor.GrizzlyMonitoring;

import fish.payara.monitoring.collect.MonitoringDataCollection;
import fish.payara.monitoring.collect.MonitoringDataCollector;
import fish.payara.monitoring.collect.MonitoringDataSource;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.glassfish.api.FutureProvider;
import org.glassfish.api.StartupRunLevel;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.container.EndpointRegistrationException;
import org.glassfish.api.container.RequestDispatcher;
import org.glassfish.api.container.Adapter;
import org.glassfish.api.deployment.ApplicationContainer;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.event.Events;
import org.glassfish.api.event.RestrictTo;
import org.glassfish.common.util.Constants;
import org.glassfish.external.statistics.CountStatistic;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.config.GenericGrizzlyListener;
import org.glassfish.grizzly.config.dom.NetworkConfig;
import org.glassfish.grizzly.config.dom.NetworkListener;
import org.glassfish.grizzly.config.dom.NetworkListeners;
import org.glassfish.grizzly.config.dom.Protocol;
import org.glassfish.grizzly.http.HttpCodecFilter;
import org.glassfish.grizzly.http.HttpProbe;
import org.glassfish.grizzly.http.server.HttpHandler;
import org.glassfish.grizzly.http.server.util.Mapper;
import org.glassfish.grizzly.impl.FutureImpl;
import org.glassfish.grizzly.utils.Futures;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.PreDestroy;
import org.glassfish.hk2.api.Rank;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.runlevel.RunLevel;
import org.glassfish.kernel.KernelLoggerInfo;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.ObservableBean;
import org.jvnet.hk2.config.Transactions;
import org.glassfish.api.container.GrizzlyNetworkListenerRestartAdapter;

/**
 * The Network Service is responsible for starting grizzly and register the
 * top level proxy. It is also providing a runtime service where other
 * services (like admin for instance) can register endpoints proxy to
 * particular context root.
 *
 * @author Jerome Dochez
 */
@Service
@RunLevel(StartupRunLevel.VAL)
@Rank(Constants.IMPORTANT_RUN_LEVEL_SERVICE)
public class GrizzlyService implements RequestDispatcher, PostConstruct, PreDestroy, EventListener,
        FutureProvider>, MonitoringDataSource {

    @Inject @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
    Config config;

    @Inject
    private ServiceLocator serviceLocator;

    @Inject
    private MonitoringService monitoringService;

    @Inject
    Transactions transactions;

    @Inject
    Events events;

    private static final Logger LOGGER = KernelLoggerInfo.getLogger();

    private final Collection proxies = new LinkedBlockingQueue<>();

    volatile List>> futures;

    Collection hosts = new ArrayList<>();

    private final GrizzlyMonitoring monitoring;

    private static final String NETWORK_CONFIG_PREFIX = "";

    private final Set mapperUpdateListeners =
            Collections.newSetFromMap(
            new ConcurrentHashMap());

    /**
     * HTTP Mapper update lock.
     */
    private final ReentrantReadWriteLock mapperLock =
            new ReentrantReadWriteLock();

    private DynamicConfigListener configListener;

    // Future to be set on server READY_EVENT
    private final FutureImpl serverReadyFuture =
            Futures.createSafeFuture();
    // Listeners to be notified once server is in READY state.
    private final Queue> serverReadyListeners =
            new ConcurrentLinkedQueue<>();

    public GrizzlyService() {
        futures = new ArrayList<>();
        monitoring = new GrizzlyMonitoring();
    }

    static {
        MonitoringDataCollection.register(CountStatistic.class,
                (collector, count) -> collector.collect(count.getName(), count.getCount()));
    }

    @Override
    public void collect(MonitoringDataCollector collector) {
        if (!"true".equals(monitoringService.getMonitoringEnabled()) ||
            !"HIGH".equals(monitoringService.getModuleMonitoringLevels().getHttpService())) {
            return;
        }
        MonitoringDataCollector httpCollector = collector.in("http");
        httpCollector.prefix("ThreadPool").collectObject(
                monitoring.getThreadPoolStatsProvider(NETWORK_CONFIG_PREFIX), MonitoringDataCollection::collectObject);
        httpCollector.prefix("ConnectionQueue").collectObject(
                monitoring.getConnectionQueueStatsProvider(NETWORK_CONFIG_PREFIX), MonitoringDataCollection::collectObject);
        httpCollector.prefix("FileCache").collectObject(
                monitoring.getFileCacheStatsProvider(NETWORK_CONFIG_PREFIX), MonitoringDataCollection::collectObject);
    }

    /**
     * Add the new proxy to our list of proxies.
     * @param proxy new proxy to be added
     */
    public void addNetworkProxy(NetworkProxy proxy) {
        proxies.add(proxy);
    }


    /**
     * Remove the proxy from our list of proxies by listener.
     * @param listener removes the proxy associated with the specified listener
     * @return true, if proxy removed,
     *         false if no proxy was associated with the specified listener.
     */
    public boolean removeNetworkProxy(NetworkListener listener) {
        return removeNetworkProxy(lookupNetworkProxy(listener));
    }


    /**
     * Remove the proxy from our list of proxies by id.
     * @return true, if proxy on specified port was removed,
     *         false if no proxy was associated with the port.
     */
    public boolean removeNetworkProxy(String id) {
        NetworkProxy proxy = getNetworkProxy(id);
        return removeNetworkProxy(proxy);
    }

    private NetworkProxy getNetworkProxy(String id) {
        NetworkProxy proxy = null;
        for (NetworkProxy p : proxies) {
            if (p instanceof GrizzlyProxy) {
                GrizzlyProxy grizzlyProxy = (GrizzlyProxy) p;
                if (grizzlyProxy.networkListener != null &&
                        grizzlyProxy.networkListener.getName() != null &&
                        grizzlyProxy.networkListener.getName().equals(id)) {
                    proxy = p;
                    break;
                }
            }
        }

        return proxy;
    }

    public boolean closeNetworkProxy(NetworkProxy proxy) {
        if (proxy != null) {
            try {
                proxy.stop();
            } catch (IOException e) {
                LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyStopProxy, e);
            }

            proxy.destroy();
            return true;
        }

        return false;
    }

    /**
     * Remove the  proxy from our list of proxies.
     * @return true, if proxy on specified port was removed,
     *         false otherwise.
     */
    public boolean removeNetworkProxy(NetworkProxy proxy) {
        return proxies.remove(proxy);
    }

    /**
     * Lookup {@link GrizzlyProxy}, which corresponds to the {@link NetworkListener}.
     *
     * @param listener {@link NetworkListener}.
     * @return {@link GrizzlyProxy}, or null, if correspondent {@link GrizzlyProxy} wasn't found.
     */
    public NetworkProxy lookupNetworkProxy(NetworkListener listener) {
        int listenerPort = -1;
        InetAddress address = null;
        try {
            listenerPort = Integer.parseInt(listener.getPort());
        } catch (NumberFormatException e) {
            LOGGER.log(Level.FINE, e.toString());
        }

        try {
            address = InetAddress.getByName(listener.getAddress());
        } catch (UnknownHostException uhe) {
            LOGGER.log(Level.FINE, uhe.toString());
        }

        if (listenerPort != -1) {
            for (NetworkProxy p : proxies) {
                if (p.getPort() == listenerPort && p.getAddress().equals(address)) {
                    return p;
                }
            }
        }

        final String listenerId = listener.getName();

        for (NetworkProxy p : proxies) {
            if (p instanceof GrizzlyProxy) {
                GrizzlyProxy grizzlyProxy = (GrizzlyProxy) p;
                if (grizzlyProxy.networkListener != null &&
                        grizzlyProxy.networkListener.getName() != null &&
                        grizzlyProxy.networkListener.getName().equals(listenerId)) {
                    return p;
                }
            }
        }

        return null;

    }

    /**
     * Restart {@link NetworkListener}.
     *
     * @param networkListenerName
     * @param timeout restart timeout, if timeout value is negative - then no timeout will be applied.
     * @param timeUnit restart timeout unit
     *
     * @throws TimeoutException thrown if timeout had expired before server succeeded to restart
     * @throws IOException
     */
    public void restartNetworkListener(String networkListenerName,
            long timeout, TimeUnit timeUnit) throws IOException, TimeoutException {
        restartNetworkListener(
                config.getNetworkConfig().getNetworkListener(networkListenerName),
                timeout, timeUnit);
    }

    /**
     * Restart {@link NetworkListener}.
     *
     * @param networkListener {@link NetworkListener}
     * @param timeout restart timeout, if timeout value is negative - then no timeout will be applied.
     * @param timeUnit restart timeout unit
     *
     * @throws TimeoutException thrown if timeout had expired before server succeeded to restart
     * @throws IOException
     */
    public void restartNetworkListener(NetworkListener networkListener,
            long timeout, TimeUnit timeUnit) throws IOException, TimeoutException {

        // Restart GrizzlyProxy on the address/port
        // Address/port/id could have been changed - so try to find
        // corresponding proxy both ways
        NetworkProxy proxy = lookupNetworkProxy(networkListener);
        Map, List> filterToProbeMapping = new HashMap<>();
        if (proxy == null) {
            proxy = getNetworkProxy(networkListener.getName());
        }
        if (proxy != null) {
            if (proxy instanceof GrizzlyProxy) {
                GrizzlyProxy grizzlyProxy = (GrizzlyProxy)proxy;
                GenericGrizzlyListener grizzlyListener = (GenericGrizzlyListener) grizzlyProxy.getUnderlyingListener();
                List codecFilters = grizzlyListener.getFilters(HttpCodecFilter.class);
                if (codecFilters != null && !codecFilters.isEmpty()) {
                    for (HttpCodecFilter codecFilter : codecFilters) {
                        HttpProbe[] probes = codecFilter.getMonitoringConfig().getProbes();
                        if (probes != null) {
                            List probesForType = filterToProbeMapping.get(codecFilter.getClass());
                            if (probesForType == null) {
                                probesForType = new ArrayList<>(4);
                                filterToProbeMapping.put(codecFilter.getClass(), probesForType);
                            }
                            Collections.addAll(probesForType, probes);
                        }
                    }
                }
            }

            closeNetworkProxy(proxy);
        }
        final Future future = createNetworkProxy(networkListener);
        removeNetworkProxy(proxy);

        if (future == null) {
            LOGGER.log(Level.FINE, "Skipping proxy registration for the listener {0}",
                    networkListener.getName());
            return;
        }

        try {
            if (timeout <= 0) {
                future.get();
            } else {
                future.get(timeout, timeUnit);
            }

            NetworkProxy newNetworkProxy = getNetworkProxy(networkListener.getName());
            if (newNetworkProxy instanceof GrizzlyProxy) {
                GrizzlyProxy grizzlyProxy = (GrizzlyProxy)newNetworkProxy;
                GenericGrizzlyListener grizzlyListener = (GenericGrizzlyListener)grizzlyProxy.getUnderlyingListener();
                if (!filterToProbeMapping.isEmpty()) {
                    for (Entry, List> entry : filterToProbeMapping.entrySet()) {
                        Class aClass = entry.getKey();
                        List filters = grizzlyListener.getFilters(aClass);
                        if (filters != null && !filters.isEmpty()) {
                            if (filters.size() != 1) {
                                throw new IllegalStateException();
                            }
                            final List probes = entry.getValue();
                            filters.get(0).getMonitoringConfig().addProbes(probes.toArray(new HttpProbe[probes.size()]));
                        }
                    }
                }
            }
        } catch (ExecutionException e) {
            throw new IOException(e.getCause());
        } catch (InterruptedException e) {
            throw new IOException(e);
        }

        registerContainerAdapters();
    }

    /**
     * Is there any {@link MapperUpdateListener} registered?
     */
    public boolean hasMapperUpdateListener(){
        return !mapperUpdateListeners.isEmpty();
    }

    /**
     * Adds {@link MapperUpdateListener} to listeners queue.
     *
     * @param listener the listener to be added.
     * @return true, if listener was successfully added,
     * or false otherwise.
     */
    public boolean addMapperUpdateListener(MapperUpdateListener listener) {
        return mapperUpdateListeners.add(listener);
    }

    /**
     * Removes {@link MapperUpdateListener} to listeners queue.
     *
     * @param listener the listener to be removed.
     * @return true, if listener was successfully removed,
     * or false otherwise.
     */
    public boolean removeMapperUpdateListener(MapperUpdateListener listener) {
        return mapperUpdateListeners.remove(listener);
    }

    /**
     * Notify all {@link MapperUpdateListener}s about update happened.
     *
     * @param networkListener {@link NetworkListener}, which {@link Mapper} got changed
     * @param mapper new {@link Mapper} value
     */
    public void notifyMapperUpdateListeners(NetworkListener networkListener,
            Mapper mapper) {
        final HttpService httpService = config.getHttpService();
        for(MapperUpdateListener listener : mapperUpdateListeners) {
            listener.update(httpService, networkListener, mapper);
        }
    }

    /**
     * Returns HTTP {@link Mapper} lock to prevent concurrent access to a
     * {@link Mapper} object.
     */
    public ReentrantReadWriteLock obtainMapperLock() {
        return mapperLock;
    }

    /**
     * Gets the logger.
     *
     * @return the logger
     */
    public Logger getLogger() {
        return LOGGER;
    }


    /**
     * Gets the habitat.
     *
     * @return the habitat
     */
    public ServiceLocator getHabitat() {
        return serviceLocator;
    }

    public GrizzlyMonitoring getMonitoring() {
        return monitoring;
    }

    /**
     * Return the {@link Future}, that might be used to monitor server startup state.
     */
    final Future getServerReadyFuture() {
        return serverReadyFuture;
    }

    /**
     * Add the {@link Callable} listener, which will be notified once server
     * state switches to "SERVER_READY".
     *
     * @param listener {@link Callable} listener.
     */
    final void addServerReadyListener(final Callable listener) {
        if (serverReadyFuture.isDone()) {
            try {
                listener.call();
            } catch (Exception ignored) {
            }

            return;
        }

        serverReadyListeners.add(listener);

        if (serverReadyFuture.isDone() && serverReadyListeners.remove(listener)) {
            try {
                listener.call();
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * Removes the {@link Callable} listener, which will be notified once server
     * state switches to "SERVER_READY".
     *
     * @param listener {@link Callable} listener.
     */
    final boolean removeServerListener(final Callable listener) {
        return serverReadyListeners.remove(listener);
    }

    /**
     * Method is invoked each time Glassfish state changes.
     */
    @Override
    public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) EventListener.Event event) {
        if (event.is(EventTypes.SERVER_READY)) {
            serverReadyFuture.result(Boolean.TRUE);

            Callable listener;
            while((listener = serverReadyListeners.poll()) != null) {
                try {
                    listener.call();
                } catch (Exception ignored) {
                }
            }
        }
    }

    /**
     * The component has been injected with any dependency and
     * will be placed into commission by the subsystem.
     */
    @Override
    public void postConstruct() {
        events.register(this);

        final NetworkConfig networkConfig = config.getNetworkConfig();
        configListener = new DynamicConfigListener(config, LOGGER);
        ObservableBean bean = (ObservableBean) ConfigSupport.getImpl(networkConfig.getNetworkListeners());
        bean.addListener(configListener);
        bean = (ObservableBean) ConfigSupport.getImpl(config.getHttpService());
        bean.addListener(configListener);
        transactions.addListenerForType(SystemProperty.class, configListener);
        configListener.setGrizzlyService(this);

        try {
            boolean isAtLeastOneProxyStarted = false;

            futures = new ArrayList<>();

            // Record how long it took for the listeners to start up
            final long startTime = System.currentTimeMillis();

            // Keep a list of successfully started listeners
            List startedListeners = new ArrayList<>();
            for (NetworkListener listener : networkConfig.getNetworkListeners().getNetworkListener()) {
                if (createNetworkProxy(listener) != null) {
                    isAtLeastOneProxyStarted = true;
                    startedListeners.add(listener);
                }
            }

            if (isAtLeastOneProxyStarted) {

                // Get the startup time
                final long startupTime = System.currentTimeMillis() - startTime;

                // Log the listeners which started.
                String boundAddresses = Arrays.toString(
                        startedListeners.stream()
                            .map(listener -> listener.getName() + ":" + getRealPort(listener))
                            .collect(Collectors.toList())
                        .toArray());
                LOGGER.log(Level.INFO, KernelLoggerInfo.grizzlyStarted,
                        new Object[] { Grizzly.getDotedVersion(), startupTime, boundAddresses });
                registerContainerAdapters();
            }
        } catch(RuntimeException e) { // So far postConstruct can not throw any other exception type
            LOGGER.log(Level.SEVERE, KernelLoggerInfo.grizzlyCantStart, e);
            for(NetworkProxy proxy : proxies) {
                try {
                    proxy.stop();
                } catch(Exception proxyStopException) {
                    LOGGER.log(Level.SEVERE, KernelLoggerInfo.grizzlyCloseException,
                            new Object[] {proxy.getPort(), proxyStopException});
                }
            }

            throw e;
        }

        registerMonitoringStatsProviders();
    }

    public int getRealPort(NetworkListener listener) {
        NetworkProxy proxy = lookupNetworkProxy(listener);
        if (proxy == null) {
            proxy = getNetworkProxy(listener.getName());
        }
        if (proxy != null) {
            if (proxy instanceof GrizzlyProxy) {
                GrizzlyProxy grizzlyProxy = (GrizzlyProxy) proxy;
                return grizzlyProxy.getPort();
            }
        }
        return Integer.parseInt(listener.getPort());
    }

    @Override
    public List>> getFutures() {
        return futures;
    }

    /*
     * Creates a new NetworkProxy for a particular HttpListner
     * @param listener NetworkListener
     * @param networkConfig HttpService
     */
    public synchronized Future> createNetworkProxy(NetworkListener listener) {

        if (!Boolean.valueOf(listener.getEnabled())) {
            addChangeListener(listener); // in case the listener will be enabled

            LOGGER.log(Level.INFO, KernelLoggerInfo.grizzlyPortDisabled,
                    new Object[]{listener.getName(), listener.getPort()});
            return null;
        }

        // create the proxy for the port.
        GrizzlyProxy proxy = new GrizzlyProxy(this, listener);

        Future> future = null;

        try {
            proxy.initialize();

            if (!isLightWeightListener(listener)) {
                final NetworkConfig networkConfig = listener.getParent(NetworkListeners.class).getParent(NetworkConfig.class);
                // attach all virtual servers to this port
                for (VirtualServer vs : networkConfig.getParent(Config.class).getHttpService().getVirtualServer()) {
                    List vsListeners =
                            StringUtils.parseStringList(vs.getNetworkListeners(), " ,");
                    if (vsListeners == null || vsListeners.isEmpty()
                            || vsListeners.contains(listener.getName())) {
                        if (!hosts.contains(vs.getId())) {
                            hosts.add(vs.getId());
                        }
                    }
                }
                addChangeListener(listener);
                addChangeListener(listener.findThreadPool());
                addChangeListener(listener.findTransport());

                final Protocol protocol = listener.findHttpProtocol();
                if (protocol != null) {
                    addChangeListener(protocol);
                    addChangeListener(protocol.getHttp());
                    addChangeListener(protocol.getHttp().getFileCache());
                    addChangeListener(protocol.getSsl());
                }
            }

            future = proxy.start();

            // add the new proxy to our list of proxies.
            proxies.add(proxy);
        } catch (Throwable e) {
            final Future> errorFuture =
                    Futures.createReadyFuture(new Result(e));
            future = errorFuture;
        } finally {
            if (future == null) {
                final FutureImpl> errorFuture =
                        Futures.>createUnsafeFuture();
                errorFuture.result(new Result(
                        new IllegalStateException("Unexpected error")));
                future = errorFuture;
            }

            futures.add(future);
        }

        return future;
    }

    private void addChangeListener(ConfigBeanProxy bean) {
        if(bean != null) {
            ((ObservableBean) ConfigSupport.getImpl(bean)).addListener(configListener);
        }
    }


    /*
     * Registers all proxies
     */
    void registerContainerAdapters() {
        for (Adapter subAdapter : serviceLocator.getAllServices(Adapter.class)) {
            //@TODO change EndportRegistrationException processing if required
            try {
                if (!subAdapter.isRegistered()) {
                    registerAdapter(subAdapter);
                    subAdapter.setRegistered(true);
                }
            } catch(EndpointRegistrationException e) {
                LOGGER.log(Level.WARNING,
                        KernelLoggerInfo.grizzlyEndpointRegistration, e);
            }
        }
        serviceLocator.getAllServices(GrizzlyNetworkListenerRestartAdapter.class).forEach(GrizzlyNetworkListenerRestartAdapter::restartEndpoints);
    }


    /**
     * The component is about to be removed from commission
     */
    @Override
    public void preDestroy() {
        for (NetworkProxy proxy : proxies) {
            try {
                proxy.stop();
            } catch (IOException e) {
                LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyStopProxy, e);
            }
        }
        unregisterMonitoringStatsProviders();
    }

    /*
     * Registers a new endpoint (proxy implementation) for a particular
     * context-root. All request coming with the context root will be dispatched
     * to the proxy instance passed in.
     * @param contextRoot for the proxy
     * @param endpointAdapter servicing requests.
     */
    @Override
    public void registerEndpoint(String contextRoot, HttpHandler endpointAdapter,
                                 ApplicationContainer container) throws EndpointRegistrationException {

        registerEndpoint(contextRoot, endpointAdapter, container, null);
    }

    /*
     * Registers a new endpoint (proxy implementation) for a particular
     * context-root. All request coming with the context root will be dispatched
     * to the proxy instance passed in.
     * @param contextRoot for the proxy
     * @param endpointAdapter servicing requests.
     * @param application container
     * @param virtualServers comma separated list of the virtual servers
     */
    @Override
    public void registerEndpoint(String contextRoot, HttpHandler endpointAdapter,
        ApplicationContainer container, String virtualServers) throws EndpointRegistrationException {
        List virtualServerList;
        if (virtualServers == null) {
            virtualServerList =
                config.getHttpService().getNonAdminVirtualServerList();
        } else{
            virtualServerList =
                StringUtils.parseStringList(virtualServers, ",");
        }
        registerEndpoint(contextRoot, virtualServerList, endpointAdapter, container);
    }


    /*
     * Registers a new endpoint (proxy implementation) for a particular
     * context-root. All request coming with the context root will be dispatched
     * to the proxy instance passed in.
     * @param contextRoot for the proxy
     * @param endpointAdapter servicing requests.
     */

    @Override
    public void registerEndpoint(String contextRoot, Collection vsServers, HttpHandler endpointAdapter,
        ApplicationContainer container) throws EndpointRegistrationException {
        Collection addressInfos = getAddressInfoFromVirtualServers(vsServers);
        for (AddressInfo info : addressInfos) {
            registerEndpoint(contextRoot, info.address, info.port, vsServers, endpointAdapter, container);
        }
    }

    /**
     * Registers a new endpoint for the given context root at the given port
     * number.
     */
    @Override
    public void registerEndpoint(String contextRoot, InetAddress address, int port, Collection vsServers,
        HttpHandler endpointAdapter, ApplicationContainer container) throws EndpointRegistrationException {
        for (NetworkProxy proxy : proxies) {
            if (proxy.getPort() == port && proxy.getAddress().equals(address)) {
                proxy.registerEndpoint(contextRoot, vsServers, endpointAdapter, container);
            }
        }
    }

    /**
     * Registers a new endpoint for the given context root at the given port
     * number.
     */
//    @Override
    public void registerEndpoint(final Endpoint endpoint) throws EndpointRegistrationException {
        final InetAddress address = endpoint.getAddress();
        final int port = endpoint.getPort();

        for (NetworkProxy proxy : proxies) {
            if (proxy.getPort() == port && proxy.getAddress().equals(address)) {
                proxy.registerEndpoint(endpoint);
            }
        }
    }

    /**
     * Removes the context-root from our list of endpoints.
     */
    @Override
    public void unregisterEndpoint(String contextRoot) throws EndpointRegistrationException {
        unregisterEndpoint(contextRoot, null);
    }

    /**
     * Removes the context-root from our list of endpoints.
     */
    @Override
    public void unregisterEndpoint(String contextRoot,
            ApplicationContainer app) throws EndpointRegistrationException {
        for (NetworkProxy proxy : proxies) {
            proxy.unregisterEndpoint(contextRoot, app);
        }
    }

    /**
     * Probe provider that implements each probe provider method as a
     * no-op.
     */
    @SuppressWarnings({"UnusedDeclaration"})
    public static class NoopInvocationHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            // Deliberate no-op
            return null;
        }
    }

    protected void registerMonitoringStatsProviders() {
        monitoring.registerThreadPoolStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.registerKeepAliveStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.registerFileCacheStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.registerConnectionQueueStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
    }

    protected void unregisterMonitoringStatsProviders() {
        monitoring.unregisterThreadPoolStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.unregisterKeepAliveStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.unregisterFileCacheStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
        monitoring.unregisterConnectionQueueStatsProviderGlobal(NETWORK_CONFIG_PREFIX);
    }

    private void registerAdapter(org.glassfish.api.container.Adapter a) throws EndpointRegistrationException {
        Endpoint endpoint = Endpoint.createEndpoint(a);
        registerEndpoint(endpoint);
    }

    // get the ports from the http listeners that are associated with
    // the virtual servers
    private List getAddressInfoFromVirtualServers(Collection virtualServers) {
        List addressInfos = new ArrayList<>();
        List networkListenerList = config.getNetworkConfig().getNetworkListeners().getNetworkListener();

        for (String vs : virtualServers) {
            VirtualServer virtualServer =
                config.getHttpService().getVirtualServerByName(vs);
            if (virtualServer == null) {
                // non-existent virtual server
                LOGGER.log(Level.WARNING, KernelLoggerInfo.grizzlyNonExistentVS, vs);
                continue;
            }
            String vsNetworkListeners = virtualServer.getNetworkListeners();
            List vsNetworkListenerList =
                StringUtils.parseStringList(vsNetworkListeners, ",");
            if (vsNetworkListenerList != null && !vsNetworkListenerList.isEmpty()) {
                for (String vsNetworkListener : vsNetworkListenerList) {
                    for (NetworkListener networkListener : networkListenerList) {
                        if (networkListener.getName().equals(vsNetworkListener) &&
                            Boolean.valueOf(networkListener.getEnabled())) {
                            addressInfos.add(new AddressInfo(networkListener.getAddress(),
                                                             networkListener.getPort()));
                            break;
                        }
                    }
                }
            }
        }
        return addressInfos;
    }

    static boolean isLightWeightListener(final NetworkListener listener) {
        return "proxy".equalsIgnoreCase(listener.getType()) ||
                "light-weight-listener".equalsIgnoreCase(listener.getProtocol());
    }

    // ---------------------------------------------------------- Nested Classes


    private static final class AddressInfo {

        private InetAddress address;
        private final int port;

        private AddressInfo(String address, String port) {
            this.port = Integer.parseInt(port);
            try {
                this.address = InetAddress.getByName(address);
            } catch (UnknownHostException ignore) {
            }
        }

    } // END AddressInfo
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy