Skip to content

Commit

Permalink
Register a servlet automatically if WCs present (#5331)
Browse files Browse the repository at this point in the history
Fixes #5070
  • Loading branch information
Denis authored Mar 25, 2019
1 parent f09516e commit 086ec83
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@
*/
package com.vaadin.flow.server.startup;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Optional;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -35,6 +36,7 @@
import com.vaadin.flow.server.DeploymentConfigurationFactory;
import com.vaadin.flow.server.VaadinServlet;
import com.vaadin.flow.server.VaadinServletConfiguration;
import com.vaadin.flow.server.webcomponent.WebComponentConfigurationRegistry;

/**
* Context listener that automatically registers Vaadin servlets.
Expand Down Expand Up @@ -65,8 +67,7 @@
public class ServletDeployer implements ServletContextListener {
private static final String SKIPPING_AUTOMATIC_SERVLET_REGISTRATION_BECAUSE = "Skipping automatic servlet registration because";

private static class StubServletConfig
implements ServletConfig {
private static class StubServletConfig implements ServletConfig {
private final ServletContext context;
private final ServletRegistration registration;

Expand Down Expand Up @@ -144,7 +145,8 @@ private DeploymentConfiguration createDeploymentConfiguration(
ServletConfig servletConfig, Class<?> servletClass) {
try {
return DeploymentConfigurationFactory
.createPropertyDeploymentConfiguration(servletClass, servletConfig);
.createPropertyDeploymentConfiguration(servletClass,
servletConfig);
} catch (ServletException e) {
throw new IllegalStateException(String.format(
"Failed to get deployment configuration data for servlet with name '%s' and class '%s'",
Expand All @@ -153,9 +155,16 @@ private DeploymentConfiguration createDeploymentConfiguration(
}

private void createAppServlet(ServletContext context) {
if (!ApplicationRouteRegistry.getInstance(context).hasNavigationTargets()) {
boolean createServlet = ApplicationRouteRegistry.getInstance(context)
.hasNavigationTargets();

createServlet = createServlet || WebComponentConfigurationRegistry
.getInstance(context).hasExporters();

if (!createServlet) {
getLogger().info(
"{} there are no navigation targets registered to the registry",
"{} there are no navigation targets registered to the "
+ "route registry and there are no web component exporters",
SKIPPING_AUTOMATIC_SERVLET_REGISTRATION_BECAUSE);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package com.vaadin.flow.server.webcomponent;

import javax.servlet.ServletContext;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -26,6 +25,8 @@
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import javax.servlet.ServletContext;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.WebComponentExporter;
import com.vaadin.flow.component.webcomponent.WebComponentConfiguration;
Expand All @@ -47,10 +48,8 @@ public class WebComponentConfigurationRegistry implements Serializable {
*/
private final ReentrantLock configurationLock = new ReentrantLock(true);

private HashMap<String, Class<? extends WebComponentExporter<?
extends Component>>> exporterClasses = null;
private HashMap<String, WebComponentConfigurationImpl<? extends Component>>
builderCache = new HashMap<>();
private HashMap<String, Class<? extends WebComponentExporter<? extends Component>>> exporterClasses = null;
private HashMap<String, WebComponentConfigurationImpl<? extends Component>> builderCache = new HashMap<>();

/**
* Protected constructor for internal OSGi extensions.
Expand All @@ -63,23 +62,25 @@ protected WebComponentConfigurationRegistry() {
* registered.
*
* @param tag
* custom element tag
* custom element tag
* @return Optional containing a web component matching given tag
*/
public Optional<WebComponentConfiguration<? extends Component>> getConfiguration(String tag) {
public Optional<WebComponentConfiguration<? extends Component>> getConfiguration(
String tag) {
return Optional.ofNullable(getConfigurationInternal(tag));
}

/**
* Retrieves {@link WebComponentConfigurationImpl} matching the {@code} tag. If the
* builder is not readily available, attempts to construct it from the
* web component exporter cache.
* Retrieves {@link WebComponentConfigurationImpl} matching the {@code} tag.
* If the builder is not readily available, attempts to construct it from
* the web component exporter cache.
*
* @param tag
* tag name of the web component
* tag name of the web component
* @return {@link WebComponentConfigurationImpl} by the tag
*/
protected WebComponentConfigurationImpl<? extends Component> getConfigurationInternal(String tag) {
protected WebComponentConfigurationImpl<? extends Component> getConfigurationInternal(
String tag) {
WebComponentConfigurationImpl<? extends Component> builder = null;
configurationLock.lock();
try {
Expand All @@ -97,11 +98,14 @@ protected WebComponentConfigurationImpl<? extends Component> getConfigurationInt
* Get an unmodifiable set containing all registered web component
* configurations for a specific {@link Component} type.
*
* @param componentClass type of the exported {@link Component}
* @param <T> component
* @return set of {@link WebComponentConfiguration} or an empty set.
* @param componentClass
* type of the exported {@link Component}
* @param <T>
* component
* @return set of {@link WebComponentConfiguration} or an empty set.
*/
public <T extends Component> Set<WebComponentConfiguration<T>> getConfigurationsByComponentType(Class<T> componentClass) {
public <T extends Component> Set<WebComponentConfiguration<T>> getConfigurationsByComponentType(
Class<T> componentClass) {
configurationLock.lock();
try {
if (exporterClasses == null) {
Expand All @@ -112,7 +116,7 @@ public <T extends Component> Set<WebComponentConfiguration<T>> getConfigurations
}
return Collections.unmodifiableSet(builderCache.values().stream()
.filter(b -> componentClass.equals(b.getComponentClass()))
.map(b -> (WebComponentConfiguration<T>)b)
.map(b -> (WebComponentConfiguration<T>) b)
.collect(Collectors.toSet()));

} finally {
Expand All @@ -124,10 +128,10 @@ public <T extends Component> Set<WebComponentConfiguration<T>> getConfigurations
* Internal method for updating registry.
*
* @param exporters
* map of web component exporters to register
* map of web component exporters to register
*/
protected void updateRegistry(Map<String, Class<?
extends WebComponentExporter<? extends Component>>> exporters) {
protected void updateRegistry(
Map<String, Class<? extends WebComponentExporter<? extends Component>>> exporters) {
configurationLock.lock();
try {
if (exporters.isEmpty()) {
Expand All @@ -151,11 +155,11 @@ protected void updateRegistry(Map<String, Class<?
* false.
*
* @param exporters
* map of web component exporters to register
* map of web component exporters to register
* @return true if set successfully or false if not set
*/
public boolean setExporters(Map<String, Class<?
extends WebComponentExporter<? extends Component>>> exporters) {
public boolean setExporters(
Map<String, Class<? extends WebComponentExporter<? extends Component>>> exporters) {
configurationLock.lock();
try {
if (exporterClasses != null) {
Expand All @@ -171,15 +175,20 @@ public boolean setExporters(Map<String, Class<?
}

public boolean hasExporters() {
return exporterClasses != null;
configurationLock.lock();
try {
return exporterClasses != null;
} finally {
configurationLock.unlock();
}
}

/**
* Get an unmodifiable set containing all registered web component
* configurations.
*
* @return unmodifiable set of web component builders in registry or
* empty set
* @return unmodifiable set of web component builders in registry or empty
* set
*/
public Set<WebComponentConfiguration<? extends Component>> getConfigurations() {
configurationLock.lock();
Expand All @@ -188,8 +197,8 @@ public Set<WebComponentConfiguration<? extends Component>> getConfigurations() {
populateCacheWithMissingConfigurations();
}

return Collections.unmodifiableSet(new HashSet<>(
builderCache.values()));
return Collections
.unmodifiableSet(new HashSet<>(builderCache.values()));
} finally {
configurationLock.unlock();
}
Expand All @@ -199,7 +208,7 @@ public Set<WebComponentConfiguration<? extends Component>> getConfigurations() {
* Get WebComponentRegistry instance for given servlet context.
*
* @param servletContext
* servlet context to get registry for
* servlet context to get registry for
* @return WebComponentRegistry instance
*/
public static WebComponentConfigurationRegistry getInstance(
Expand All @@ -208,14 +217,14 @@ public static WebComponentConfigurationRegistry getInstance(

Object attribute;
synchronized (servletContext) {
attribute = servletContext
.getAttribute(WebComponentConfigurationRegistry.class.getName());
attribute = servletContext.getAttribute(
WebComponentConfigurationRegistry.class.getName());

if (attribute == null) {
attribute = createRegistry(servletContext);
servletContext
.setAttribute(WebComponentConfigurationRegistry.class.getName(),
attribute);
servletContext.setAttribute(
WebComponentConfigurationRegistry.class.getName(),
attribute);
}
}

Expand All @@ -227,12 +236,14 @@ public static WebComponentConfigurationRegistry getInstance(
}
}

private static WebComponentConfigurationRegistry createRegistry(ServletContext context) {
private static WebComponentConfigurationRegistry createRegistry(
ServletContext context) {
if (OSGiAccess.getInstance().getOsgiServletContext() == null) {
return new WebComponentConfigurationRegistry();
}
Object attribute = OSGiAccess.getInstance().getOsgiServletContext()
.getAttribute(WebComponentConfigurationRegistry.class.getName());
.getAttribute(
WebComponentConfigurationRegistry.class.getName());
if (attribute != null
&& attribute instanceof OSGiWebComponentConfigurationRegistry) {
return (WebComponentConfigurationRegistry) attribute;
Expand All @@ -245,7 +256,8 @@ private static WebComponentConfigurationRegistry createRegistry(ServletContext c
* Adds a builder to the builder cache if one is not already present,
* exporters have been set, and a matching exporter is found.
*
* @param tag name of the web component
* @param tag
* name of the web component
*/
protected void populateCacheByTag(String tag) {
configurationLock.lock();
Expand All @@ -255,11 +267,12 @@ protected void populateCacheByTag(String tag) {
return;
}

Class<? extends WebComponentExporter<? extends Component>> exporterClass
= exporterClasses.get(tag);
Class<? extends WebComponentExporter<? extends Component>> exporterClass = exporterClasses
.get(tag);

if (exporterClass != null) {
builderCache.put(tag, constructConfigurations(tag, exporterClass));
builderCache.put(tag,
constructConfigurations(tag, exporterClass));
// remove the class reference from the data bank - it has
// already been constructed and is no longer needed
exporterClasses.remove(tag);
Expand Down Expand Up @@ -287,22 +300,21 @@ protected boolean areAllConfigurationsAvailable() {
configurationLock.lock();

try {
return exporterClasses != null &&
exporterClasses.size() == 0;
return exporterClasses != null && exporterClasses.size() == 0;
} finally {
configurationLock.unlock();
}
}

protected WebComponentConfigurationImpl<? extends Component> constructConfigurations(
String tag, Class<? extends WebComponentExporter<?
extends Component>> exporterClass) {
String tag,
Class<? extends WebComponentExporter<? extends Component>> exporterClass) {

Instantiator instantiator =
VaadinService.getCurrent().getInstantiator();
Instantiator instantiator = VaadinService.getCurrent()
.getInstantiator();

WebComponentExporter<? extends Component> exporter =
instantiator.getOrCreate(exporterClass);
WebComponentExporter<? extends Component> exporter = instantiator
.getOrCreate(exporterClass);

return new WebComponentConfigurationImpl<>(tag, exporter);
}
Expand Down
Loading

0 comments on commit 086ec83

Please sign in to comment.