// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.jdisc.core; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.yahoo.jdisc.AbstractResource; import com.yahoo.jdisc.SharedResource; import com.yahoo.jdisc.application.BindingSet; import com.yahoo.jdisc.application.BindingSetSelector; import com.yahoo.jdisc.application.ContainerBuilder; import com.yahoo.jdisc.application.ResourcePool; import com.yahoo.jdisc.handler.RequestHandler; import com.yahoo.jdisc.service.BindingSetNotFoundException; import com.yahoo.jdisc.service.CurrentContainer; import com.yahoo.jdisc.service.NoBindingSetSelectedException; import com.yahoo.jdisc.service.ServerProvider; import java.net.URI; import java.util.Map; import java.util.logging.Logger; /** * @author Simon Thoresen */ public class ActiveContainer extends AbstractResource implements CurrentContainer { private static final Logger log = Logger.getLogger(ActiveContainer.class.getName()); private final ContainerTermination termination; private final Injector guiceInjector; private final Iterable serverProviders; private final ResourcePool resourceReferences = new ResourcePool(); private final Map> serverBindings; private final Map> clientBindings; private final BindingSetSelector bindingSetSelector; private final TimeoutManagerImpl timeoutMgr; public ActiveContainer(ContainerBuilder builder) { serverProviders = builder.serverProviders().activate(); serverProviders.forEach(resourceReferences::retain); serverBindings = builder.activateServerBindings(); serverBindings.forEach( (ignoredName, bindingSet) -> bindingSet.forEach( binding -> resourceReferences.retain(binding.getValue()))); clientBindings = builder.activateClientBindings(); clientBindings.forEach( (ignoredName, bindingSet) -> bindingSet.forEach( binding -> resourceReferences.retain(binding.getValue()))); bindingSetSelector = builder.getInstance(BindingSetSelector.class); timeoutMgr = builder.getInstance(TimeoutManagerImpl.class); timeoutMgr.start(); builder.guiceModules().install(new AbstractModule() { @Override protected void configure() { bind(TimeoutManagerImpl.class).toInstance(timeoutMgr); } }); guiceInjector = builder.guiceModules().activate(); termination = new ContainerTermination(builder.appContext()); } @Override protected void destroy() { resourceReferences.release(); timeoutMgr.shutdown(); termination.run(); } @Override protected void finalize() throws Throwable { try { int retainCount = retainCount(); if (retainCount > 0) { log.warning(this + ".destroy() invoked from finalize() not through ApplicationLoader. " + "This is an indication of either a resource leak or invalid use of reference counting. " + "Retained references as this moment: " + retainCount); destroy(); } } finally { super.finalize(); } } /** * Make this instance retain a reference to the resource until it is destroyed. */ void retainReference(SharedResource resource) { resourceReferences.retain(resource); } public ContainerTermination shutdown() { return termination; } public Injector guiceInjector() { return guiceInjector; } public Iterable serverProviders() { return serverProviders; } public Map> serverBindings() { return serverBindings; } public BindingSet serverBindings(String setName) { return serverBindings.get(setName); } public Map> clientBindings() { return clientBindings; } public BindingSet clientBindings(String setName) { return clientBindings.get(setName); } TimeoutManagerImpl timeoutManager() { return timeoutMgr; } @Override public ContainerSnapshot newReference(URI uri) { String name = bindingSetSelector.select(uri); if (name == null) { throw new NoBindingSetSelectedException(uri); } BindingSet serverBindings = serverBindings(name); BindingSet clientBindings = clientBindings(name); if (serverBindings == null || clientBindings == null) { throw new BindingSetNotFoundException(name); } return new ContainerSnapshot(this, serverBindings, clientBindings); } }