private VirtualHost normalizeDefaultVirtualHost(VirtualHost h, @Nullable SslContext defaultSslContext) { final SslContext sslCtx = h.sslContext() != null ? h.sslContext() : defaultSslContext; return new VirtualHost( h.defaultHostname(), "*", sslCtx, h.serviceConfigs().stream().map( e -> new ServiceConfig(e.pathMapping(), e.service(), e.loggerName().orElse(null))) .collect(Collectors.toList()), h.producibleMediaTypes(), rejectedPathMappingHandler, host -> h.accessLogger()); }
@Override public Server server() { return cfg.server(); }
/** * Finds the {@link List} of {@link VirtualHost}s that contains the specified {@link Service}. If there's * no match, an empty {@link List} is returned. Note that this is potentially an expensive operation and * thus should not be used in a performance-sensitive path. */ public List<VirtualHost> findVirtualHosts(Service<?, ?> service) { requireNonNull(service, "service"); @SuppressWarnings("rawtypes") final Class<? extends Service> serviceType = service.getClass(); final List<VirtualHost> res = new ArrayList<>(); for (VirtualHost h : virtualHosts) { for (ServiceConfig c : h.serviceConfigs()) { // Consider the case where the specified service is decorated before being added. final Service<?, ?> s = c.service(); @SuppressWarnings("rawtypes") final Optional<? extends Service> sOpt = s.as(serviceType); if (!sOpt.isPresent()) { continue; } if (sOpt.get() == service) { res.add(c.virtualHost()); break; } } } return res; }
ServiceConfig build(VirtualHost virtualHost) { requireNonNull(virtualHost, "virtualHost"); return new ServiceConfig(virtualHost, pathMapping(), service()); }
private RequestContextAwareLogger newLogger(ServiceConfig cfg) { String loggerName = cfg.loggerName().orElse(null); if (loggerName == null) { loggerName = cfg.pathMapping().loggerName(); } return new RequestContextAwareLogger(this, LoggerFactory.getLogger( cfg.server().config().serviceLoggerPrefix() + '.' + loggerName)); }
@Override public ServiceSpecification generateSpecification(Set<ServiceConfig> serviceConfigs) { final Map<Class<?>, EntryBuilder> map = new LinkedHashMap<>(); for (ServiceConfig c : serviceConfigs) { final THttpService service = c.service().as(THttpService.class).get(); service.entries().forEach((serviceName, entry) -> { for (Class<?> iface : entry.interfaces()) { final Class<?> serviceClass = iface.getEnclosingClass(); final EntryBuilder builder = map.computeIfAbsent(serviceClass, cls -> new EntryBuilder(serviceClass)); // Add all available endpoints. Accept only the services with exact and prefix path // mappings, whose endpoint path can be determined. final PathMapping pathMapping = c.pathMapping(); final String path = pathMapping.exactPath().orElse(pathMapping.prefix().orElse(null)); if (path != null) { builder.endpoint(new EndpointInfoBuilder(c.virtualHost().hostnamePattern(), path) .fragment(serviceName) .defaultFormat(service.defaultSerializationFormat()) .availableFormats(service.allowedSerializationFormats()) .build()); } } }); } final List<Entry> entries = map.values().stream() .map(EntryBuilder::build) .collect(Collectors.toList()); return generate(entries); }
@Override public void serviceAdded(ServiceConfig cfg) throws Exception { final MeterRegistry registry = cfg.server().meterRegistry(); if (cache != null) { CaffeineMetricSupport.setup( registry, new MeterIdPrefix("armeria.server.file.vfsCache", "hostnamePattern", cfg.virtualHost().hostnamePattern(), "pathMapping", cfg.pathMapping().meterTag(), "vfs", config.vfs().meterTag()), cache); } }
@Override public <T extends Service<HttpRequest, HttpResponse>> T service() { return cfg.service(); }
private static ServiceConfig findServiceConfig(Server server, String path, Service<?, ?> service) { for (ServiceConfig cfg : server.config().defaultVirtualHost().serviceConfigs()) { final Optional<String> exactPath = cfg.pathMapping().exactPath(); if (!exactPath.isPresent()) { continue; } if (!path.equals(exactPath.get())) { continue; } if (cfg.service().as(service.getClass()).isPresent()) { return cfg; } } throw new Error(); // Never reaches here. } }
final Service<HttpRequest, HttpResponse> service = serviceCfg.service(); final Channel channel = ctx.channel(); final InetAddress remoteAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress(); serviceCfg, channel, serviceCfg.server().meterRegistry(), protocol, mappingCtx, mappingResult, req, getSSLSession(channel), proxiedAddresses, clientAddress);
@Override public VirtualHost virtualHost() { return cfg.virtualHost(); }
@Override public PathMapping pathMapping() { return cfg.pathMapping(); }
/** * Binds the specified {@link Service} at the specified {@link PathMapping}. */ public B service(PathMapping pathMapping, Service<HttpRequest, HttpResponse> service) { services.add(new ServiceConfig(pathMapping, service, null)); return self(); }
final Map<String, ServiceEntryBuilder> map = new LinkedHashMap<>(); for (ServiceConfig serviceConfig : serviceConfigs) { final GrpcService grpcService = serviceConfig.service().as(GrpcService.class).get(); final ImmutableSet.Builder<MediaType> supportedMediaTypesBuilder = ImmutableSet.builder(); supportedMediaTypesBuilder.addAll(grpcService.supportedSerializationFormats() .stream() .map(SerializationFormat::mediaType)::iterator); if (serviceConfig.service().as(UnframedGrpcService.class).isPresent()) { if (grpcService.supportedSerializationFormats().contains(GrpcSerializationFormats.PROTO)) { if (serviceConfig.pathMapping().prefix().isPresent()) { pathPrefix = serviceConfig.pathMapping().prefix().get(); } else { pathPrefix = "/"; final String serviceName = service.getServiceDescriptor().getName(); map.get(serviceName).endpoint( new EndpointInfoBuilder(serviceConfig.virtualHost().hostnamePattern(),
@Override public void serviceAdded(ServiceConfig cfg) throws Exception { checkState(server == null, "cannot be added to more than one server"); server = cfg.server(); router = Routers.ofCompositeService(services); final MeterRegistry registry = server.meterRegistry(); final MeterIdPrefix meterIdPrefix = new MeterIdPrefix("armeria.server.router.compositeServiceCache", "hostnamePattern", cfg.virtualHost().hostnamePattern(), "pathMapping", cfg.pathMapping().meterTag()); router.registerMetrics(registry, meterIdPrefix); for (CompositeServiceEntry<I, O> e : services()) { ServiceCallbackInvoker.invokeServiceAdded(cfg, e.service()); } }
private static boolean isSupported( ServiceConfig serviceCfg, Set<Class<? extends Service<?, ?>>> supportedServiceTypes) { return supportedServiceTypes.stream().anyMatch(type -> serviceCfg.service().as(type).isPresent()); }
/** * Returns the {@link Server} the {@link #service()} belongs to. */ public Server server() { return virtualHost().server(); }
@Override public void serviceAdded(ServiceConfig cfg) throws Exception { if (paramNames != null) { final Set<String> params = cfg.pathMapping().paramNames(); // Find out if old path and new path are compatible for (String param : paramNames) { if (!params.contains(param)) { throw new IllegalArgumentException("pathParams: " + param + " (no matching param in " + params + ')'); } } // We don't need the paramNames anymore paramNames = null; } super.serviceAdded(cfg); }
/** * Binds the specified {@link Service} at the specified {@link PathMapping}. * * @deprecated Use a logging framework integration such as {@code RequestContextExportingAppender} in * {@code armeria-logback}. */ @Deprecated public B service(PathMapping pathMapping, Service<HttpRequest, HttpResponse> service, String loggerName) { services.add(new ServiceConfig(pathMapping, service, loggerName)); return self(); }
@Override public ServiceSpecification generateSpecification(Set<ServiceConfig> serviceConfigs) { final Map<Class<?>, EntryBuilder> map = new LinkedHashMap<>(); for (ServiceConfig c : serviceConfigs) { final THttpService service = c.service().as(THttpService.class).get(); service.entries().forEach((serviceName, entry) -> { for (Class<?> iface : entry.interfaces()) { final Class<?> serviceClass = iface.getEnclosingClass(); final EntryBuilder builder = map.computeIfAbsent(serviceClass, cls -> new EntryBuilder(serviceClass)); // Add all available endpoints. Accept only the services with exact and prefix path // mappings, whose endpoint path can be determined. final PathMapping pathMapping = c.pathMapping(); final String path = pathMapping.exactPath().orElse(pathMapping.prefix().orElse(null)); if (path != null) { builder.endpoint(new EndpointInfo( c.virtualHost().hostnamePattern(), path, serviceName, service.defaultSerializationFormat(), service.allowedSerializationFormats())); } } }); } final List<Entry> entries = map.values().stream() .map(EntryBuilder::build) .collect(Collectors.toList()); return generate(entries); }