package org.webpieces.router.impl.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.webpieces.router.api.routing.PortType;
import org.webpieces.router.api.routing.RouteFilter;
import org.webpieces.router.api.routing.Router;
import org.webpieces.router.api.routing.WebAppMeta;
import org.webpieces.router.impl.FilterInfo;
import org.webpieces.router.impl.ReverseRoutes;
import org.webpieces.router.impl.RouteMeta;
import org.webpieces.router.impl.StaticRoute;
import org.webpieces.router.impl.UrlPath;
import org.webpieces.util.logging.Logger;
import org.webpieces.util.logging.LoggerFactory;
public class R1RouterBuilder extends AbstractDomainBuilder {
private static final Logger log = LoggerFactory.getLogger(R2DomainRouterBuilder.class);
private L1AllRouting allRouting;
private List<StaticRoute> staticRoutes = new ArrayList<>();
private List<FilterInfo<?>> routeFilters = new ArrayList<>();
private List<FilterInfo<?>> notFoundFilters = new ArrayList<>();
private List<FilterInfo<?>> internalErrorFilters = new ArrayList<>();
public R1RouterBuilder(RouterInfo info, L1AllRouting allRouting, LogicHolder holder, boolean isHttpsOnlyRoutes) {
super(info, allRouting.getMainRoutes(), allRouting.getMainRoutes().getRoutesForDomain(), holder, isHttpsOnlyRoutes);
this.allRouting = allRouting;
}
public L1AllRouting getRouterInfo() {
return allRouting;
}
@Override
public Router getDomainScopedRouter(String domain) {
if(domain == null || domain.length() == 0)
throw new IllegalArgumentException("domain must be non-null and size greater than 0");
L2DomainRoutes routes = allRouting.getCreateDomainScoped(domain);
RouterInfo info = new RouterInfo(domain);
return new R2DomainRouterBuilder(info, routes, routes.getRoutesForDomain(), holder);
}
@Override
public <T> void addFilter(String path, Class<? extends RouteFilter<T>> filter, T initialConfig, PortType type) {
String totalPath = routerInfo.getPath()+path;
FilterInfo<T> info = new FilterInfo<>(totalPath, filter, initialConfig, type);
routeFilters.add(info);
}
@Override
public <T> void addNotFoundFilter(Class<? extends RouteFilter<T>> filter, T initialConfig, PortType type) {
FilterInfo<T> info = new FilterInfo<>("", filter, initialConfig, type);
notFoundFilters.add(info);
}
@Override
public <T> void addInternalErrorFilter(Class<? extends RouteFilter<T>> filter, T initialConfig, PortType type) {
FilterInfo<T> info = new FilterInfo<>("", filter, initialConfig, type);
internalErrorFilters.add(info);
}
@Override
public void addStaticDir(String urlPath, String fileSystemPath, boolean isOnClassPath) {
if(!urlPath.endsWith("/"))
throw new IllegalArgumentException("Static directory so urlPath must end with a /");
addStaticRoute(urlPath, fileSystemPath, isOnClassPath);
}
@Override
public void addStaticFile(String urlPath, String fileSystemPath, boolean isOnClassPath) {
if(urlPath.endsWith("/"))
throw new IllegalArgumentException("Static file so urlPath must NOT end with a /");
addStaticRoute(urlPath, fileSystemPath, isOnClassPath);
}
private void addStaticRoute(String urlPath, String fileSystemPath, boolean isOnClassPath) {
if(isOnClassPath)
throw new UnsupportedOperationException("oops, isOnClassPath not supported yet");
StaticRoute route = new StaticRoute(new UrlPath(routerInfo, urlPath), fileSystemPath, isOnClassPath, holder.getCachedCompressedDirectory());
staticRoutes.add(route);
log.info("scope:'"+routerInfo+"' adding static route="+route.getFullPath()+" fileSystemPath="+route.getFileSystemPath());
RouteMeta meta = new RouteMeta(route, holder.getInjector(), currentPackage.get(), holder.getUrlEncoding());
allRouting.addStaticRoute(meta);
}
public void applyFilters(WebAppMeta rm) {
ReverseRoutes reverseRoutes = holder.getReverseRoutes();
Collection<RouteMeta> metas = reverseRoutes.getAllRouteMetas();
for(RouteMeta meta : metas) {
String path = meta.getRoute().getFullPath();
List<FilterInfo<?>> filters = findMatchingFilters(path, meta.getRoute().isHttpsRoute());
meta.setFilters(filters);
}
List<L2DomainRoutes> allDomains = allRouting.getAllDomains();
for(L2DomainRoutes domainRoutes : allDomains) {
applyFilters(domainRoutes, rm);
}
}
private void applyFilters(L2DomainRoutes domainRoutes, WebAppMeta rm) {
String domain = domainRoutes.getDomain();
if(domain == null)
domain = "ALLOTHER";
RouteMeta notFoundMeta = domainRoutes.getPageNotFoundRoute();
RouteMeta internalErrorMeta = domainRoutes.getInternalSvrErrorRoute();
if(notFoundMeta == null)
throw new IllegalStateException("router.setNotFoundRoute MUST be called for domain="+domain+" Modules="+rm.getRouteModules());
else if(internalErrorMeta == null)
throw new IllegalStateException("router.setInternalSvrErrorRoute MUST be called for domain="+domain+". Modules="+rm.getRouteModules());
internalErrorMeta.setFilters(internalErrorFilters);
notFoundMeta.setFilters(notFoundFilters);
}
public List<StaticRoute> getStaticRoutes() {
return staticRoutes;
}
public List<FilterInfo<?>> findNotFoundFilters(String path, boolean isHttps) {
List<FilterInfo<?>> matchingFilters = new ArrayList<>();
for(FilterInfo<?> info : notFoundFilters) {
if(!info.securityMatch(isHttps))
continue; //skip this filter
matchingFilters.add(0, info);
}
return matchingFilters;
}
public List<FilterInfo<?>> findMatchingFilters(String path, boolean isHttps) {
List<FilterInfo<?>> matchingFilters = new ArrayList<>();
for(FilterInfo<?> info : routeFilters) {
if(!info.securityMatch(isHttps))
continue; //skip this filter
Pattern patternToMatch = info.getPatternToMatch();
Matcher matcher = patternToMatch.matcher(path);
if(matcher.matches()) {
matchingFilters.add(0, info);
}
}
return matchingFilters;
}
public void loadNotFoundAndErrorFilters() {
List<L2DomainRoutes> allDomains = allRouting.getAllDomains();
for(L2DomainRoutes domainRoutes : allDomains) {
loadFilters(domainRoutes);
}
}
private void loadFilters(L2DomainRoutes domainRoutes) {
RouteMeta notFound = domainRoutes.getPageNotFoundRoute();
RouteMeta internalErrorMeta = domainRoutes.getInternalSvrErrorRoute();
holder.getFinder().loadFiltersIntoMeta(notFound, notFound.getFilters(), true);
holder.getFinder().loadFiltersIntoMeta(internalErrorMeta, internalErrorMeta.getFilters(), true);
}
}