final Map<String, ServletHandler> pathServlets = new HashMap<String, ServletHandler>();
final Set<String> pathMatches = new HashSet<String>();
final Set<String> extensionMatches = new HashSet<String>();
DeploymentInfo deploymentInfo = deployment.getDeploymentInfo();
//loop through all filter mappings, and add them to the set of known paths
for (FilterMappingInfo mapping : deploymentInfo.getFilterMappings()) {
if (mapping.getMappingType() == FilterMappingInfo.MappingType.URL) {
String path = mapping.getMapping();
if(path.equals("*")) {
//UNDERTOW-95, support this non-standard filter mapping
path = "/*";
}
if (!path.startsWith("*.")) {
pathMatches.add(path);
} else {
extensionMatches.add(path.substring(2));
}
}
}
//now loop through all servlets.
for (Map.Entry<String, ServletHandler> entry : servlets.getServletHandlers().entrySet()) {
//add the servlet to the deployment
final ServletHandler handler = entry.getValue();
//add the servlet to the approprite path maps
for (String path : handler.getManagedServlet().getServletInfo().getMappings()) {
if (path.equals("/")) {
//the default servlet
pathMatches.add("/*");
if (pathServlets.containsKey("/*") || defaultServlet != null) {
throw UndertowServletMessages.MESSAGES.twoServletsWithSameMapping(path);
}
defaultServlet = handler;
defaultHandler = servletChain(handler, handler.getManagedServlet(), null);
} else if (!path.startsWith("*.")) {
//either an exact or a /* based path match
if(path.isEmpty()) {
path = "/";
}
pathMatches.add(path);
if (pathServlets.containsKey(path)) {
throw UndertowServletMessages.MESSAGES.twoServletsWithSameMapping(path);
}
pathServlets.put(path, handler);
} else {
//an extension match based servlet
String ext = path.substring(2);
extensionMatches.add(ext);
extensionServlets.put(ext, handler);
}
}
}
//we always create a default servlet, even if it is not going to have any path mappings registered
final DefaultServletConfig config = deploymentInfo.getDefaultServletConfig() == null ? new DefaultServletConfig() : deploymentInfo.getDefaultServletConfig();
DefaultServlet defaultInstance = new DefaultServlet(deployment, config, deploymentInfo.getWelcomePages());
final ServletHandler managedDefaultServlet = servlets.addServlet(new ServletInfo(DEFAULT_SERVLET_NAME, DefaultServlet.class, new ImmediateInstanceFactory<Servlet>(defaultInstance)));
if (defaultServlet == null) {
//no explicit default servlet was specified, so we register our mapping
pathMatches.add("/*");
defaultServlet = managedDefaultServlet;
defaultHandler = new ServletChain(defaultServlet, managedDefaultServlet.getManagedServlet(), null);
}
final ServletPathMatchesData.Builder builder = ServletPathMatchesData.builder();
//we now loop over every path in the application, and build up the patches based on this path
//these paths contain both /* and exact matches.
for (final String path : pathMatches) {
//resolve the target servlet, will return null if this is the default servlet
MatchData targetServletMatch = resolveServletForPath(path, pathServlets);
final Map<DispatcherType, List<ManagedFilter>> noExtension = new HashMap<DispatcherType, List<ManagedFilter>>();
final Map<String, Map<DispatcherType, List<ManagedFilter>>> extension = new HashMap<String, Map<DispatcherType, List<ManagedFilter>>>();
//initalize the extension map. This contains all the filers in the noExtension map, plus
//any filters that match the extension key
for (String ext : extensionMatches) {
extension.put(ext, new HashMap<DispatcherType, List<ManagedFilter>>());
}
//loop over all the filters, and add them to the appropriate map in the correct order
for (final FilterMappingInfo filterMapping : deploymentInfo.getFilterMappings()) {
ManagedFilter filter = filters.getManagedFilter(filterMapping.getFilterName());
if (filterMapping.getMappingType() == FilterMappingInfo.MappingType.SERVLET) {
if (targetServletMatch.handler != null) {
if (filterMapping.getMapping().equals(targetServletMatch.handler.getManagedServlet().getServletInfo().getName())) {
addToListMap(noExtension, filterMapping.getDispatcher(), filter);
for (Map<DispatcherType, List<ManagedFilter>> l : extension.values()) {
addToListMap(l, filterMapping.getDispatcher(), filter);
}
}
}
} else {
if (filterMapping.getMapping().isEmpty() || !filterMapping.getMapping().startsWith("*.")) {
if (isFilterApplicable(path, filterMapping.getMapping())) {
addToListMap(noExtension, filterMapping.getDispatcher(), filter);
for (Map<DispatcherType, List<ManagedFilter>> l : extension.values()) {
addToListMap(l, filterMapping.getDispatcher(), filter);
}
}
} else {
addToListMap(extension.get(filterMapping.getMapping().substring(2)), filterMapping.getDispatcher(), filter);
}
}
}
//resolve any matches and add them to the builder
if (path.endsWith("/*")) {
String prefix = path.substring(0, path.length() - 2);
//add the default non-extension match
builder.addPrefixMatch(prefix, createHandler(defaultHandler, defaultServlet, deploymentInfo, targetServletMatch.handler, noExtension, targetServletMatch.matchedPath));
//build up the chain for each non-extension match
for (Map.Entry<String, Map<DispatcherType, List<ManagedFilter>>> entry : extension.entrySet()) {
ServletHandler pathServlet = targetServletMatch.handler;
String pathMatch = targetServletMatch.matchedPath;
if (pathServlet == null) {
pathServlet = extensionServlets.get(entry.getKey());
}
if (pathServlet == null) {
pathServlet = defaultServlet;
}
HttpHandler handler = pathServlet;
if (!entry.getValue().isEmpty()) {
handler = new FilterHandler(entry.getValue(), deploymentInfo.isAllowNonStandardWrappers(), handler);
}
builder.addExtensionMatch(prefix, entry.getKey(), servletChain(handler, pathServlet.getManagedServlet(), pathMatch));
}
} else if (path.isEmpty()) {
//the context root match
builder.addExactMatch("/", createHandler(defaultHandler, defaultServlet, deploymentInfo, targetServletMatch.handler, noExtension, targetServletMatch.matchedPath));
} else {
//we need to check for an extension match, so paths like /exact.txt will have the correct filter applied
String lastSegment = path.substring(path.lastIndexOf('/'));
if (lastSegment.contains(".")) {
String ext = lastSegment.substring(lastSegment.lastIndexOf('.') + 1);
if (extension.containsKey(ext)) {
Map<DispatcherType, List<ManagedFilter>> extMap = extension.get(ext);
builder.addExactMatch(path, createHandler(defaultHandler, defaultServlet, deploymentInfo, targetServletMatch.handler, extMap, targetServletMatch.matchedPath));
} else {
builder.addExactMatch(path, createHandler(defaultHandler, defaultServlet, deploymentInfo, targetServletMatch.handler, noExtension, targetServletMatch.matchedPath));
}
} else {
builder.addExactMatch(path, createHandler(defaultHandler, defaultServlet, deploymentInfo, targetServletMatch.handler, noExtension, targetServletMatch.matchedPath));
}
}
}
//now setup name based mappings
//these are used for name based dispatch
for (Map.Entry<String, ServletHandler> entry : servlets.getServletHandlers().entrySet()) {
final Map<DispatcherType, List<ManagedFilter>> filtersByDispatcher = new HashMap<DispatcherType, List<ManagedFilter>>();
for (final FilterMappingInfo filterMapping : deploymentInfo.getFilterMappings()) {
ManagedFilter filter = filters.getManagedFilter(filterMapping.getFilterName());
if (filterMapping.getMappingType() == FilterMappingInfo.MappingType.SERVLET) {
if (filterMapping.getMapping().equals(entry.getKey())) {
addToListMap(filtersByDispatcher, filterMapping.getDispatcher(), filter);
}
}
}
if (filtersByDispatcher.isEmpty()) {
builder.addNameMatch(entry.getKey(), servletChain(entry.getValue(), entry.getValue().getManagedServlet(), null));
} else {
builder.addNameMatch(entry.getKey(), servletChain(new FilterHandler(filtersByDispatcher, deploymentInfo.isAllowNonStandardWrappers(), entry.getValue()), entry.getValue().getManagedServlet(), null));
}
}
builder.setDefaultServlet(defaultHandler);