Skip to content

Commit 4603dbe

Browse files
authored
Added shortcut methods for registering MediaSupport on WebServer.Builder (helidon-io#6564)
1 parent 55fff36 commit 4603dbe

4 files changed

Lines changed: 88 additions & 15 deletions

File tree

nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContext.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.Objects;
2122
import java.util.ServiceLoader;
2223

2324
import io.helidon.common.GenericType;
@@ -115,6 +116,7 @@ class Builder implements io.helidon.common.Builder<Builder, MediaContext> {
115116
private final HelidonServiceLoader.Builder<MediaSupportProvider> mediaSupportProviders;
116117
private final List<MediaSupport> explicitSupports = new ArrayList<>();
117118
private Config providersConfig;
119+
private MediaContext fallback;
118120

119121
// Builder instance must be created using factory method.
120122
private Builder() {
@@ -141,7 +143,7 @@ public MediaContext build() {
141143
supports.add(StringSupport.create());
142144
supports.add(PathSupport.create());
143145
supports.add(FormParamsSupport.create());
144-
return new MediaContextImpl(supports);
146+
return new MediaContextImpl(supports, fallback);
145147
}
146148

147149
/**
@@ -183,6 +185,18 @@ public Builder addMediaSupport(MediaSupport mediaSupport) {
183185
explicitSupports.add(mediaSupport);
184186
return this;
185187
}
188+
189+
/**
190+
* Configure an existing context as a fallback for this context.
191+
*
192+
* @param mediaContext media context to use if supports configured on this request cannot provide a good result
193+
* @return updated builder
194+
*/
195+
public Builder fallback(MediaContext mediaContext) {
196+
Objects.requireNonNull(mediaContext);
197+
this.fallback = mediaContext;
198+
return this;
199+
}
186200
}
187201

188202
}

nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextImpl.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ class MediaContextImpl implements MediaContext {
4040
private static final ConcurrentHashMap<GenericType<?>, AtomicBoolean> LOGGED_WRITERS = new ConcurrentHashMap<>();
4141

4242
private final List<MediaSupport> supports;
43+
private final MediaContext fallback;
4344

44-
MediaContextImpl(List<MediaSupport> supports) {
45+
MediaContextImpl(List<MediaSupport> supports, MediaContext fallback) {
4546
this.supports = supports;
4647
this.supports.forEach(it -> it.init(this));
48+
this.fallback = fallback;
4749
}
4850

4951
@Override
@@ -58,7 +60,11 @@ public <T> EntityReader<T> reader(GenericType<T> type, Headers headers) {
5860
}
5961
}
6062
if (compatible == null) {
61-
return FailingReader.instance();
63+
if (fallback == null) {
64+
return FailingReader.instance();
65+
} else {
66+
return fallback.reader(type, headers);
67+
}
6268
}
6369
return entityReader(compatible);
6470
}
@@ -79,7 +85,11 @@ public <T> EntityWriter<T> writer(GenericType<T> type,
7985
}
8086

8187
if (compatible == null) {
82-
return FailingWriter.instance();
88+
if (fallback == null) {
89+
return FailingWriter.instance();
90+
} else {
91+
return fallback.writer(type, requestHeaders, responseHeaders);
92+
}
8393
}
8494
return entityWriter(compatible);
8595
}
@@ -100,7 +110,11 @@ public <T> EntityReader<T> reader(GenericType<T> type,
100110
}
101111
}
102112
if (compatible == null) {
103-
return FailingReader.instance();
113+
if (fallback == null) {
114+
return FailingReader.instance();
115+
} else {
116+
return fallback.reader(type, requestHeaders, responseHeaders);
117+
}
104118
}
105119
return entityReader(compatible);
106120
}
@@ -119,7 +133,11 @@ public <T> EntityWriter<T> writer(GenericType<T> type, WritableHeaders<?> reques
119133
}
120134

121135
if (compatible == null) {
122-
return FailingWriter.instance();
136+
if (fallback == null) {
137+
return FailingWriter.instance();
138+
} else {
139+
return fallback.writer(type, requestHeaders);
140+
}
123141
}
124142
return entityWriter(compatible);
125143
}

nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.helidon.nima.common.tls.Tls;
3535
import io.helidon.nima.http.encoding.ContentEncodingContext;
3636
import io.helidon.nima.http.media.MediaContext;
37+
import io.helidon.nima.http.media.MediaSupport;
3738
import io.helidon.nima.webserver.http.DirectHandlers;
3839
import io.helidon.nima.webserver.http.HttpRouting;
3940
import io.helidon.nima.webserver.spi.ServerConnectionProvider;
@@ -170,8 +171,8 @@ class Builder implements io.helidon.common.Builder<Builder, WebServer>, Router.R
170171
private final DefaultServerConfig.Builder configBuilder = DefaultServerConfig.builder();
171172

172173
private Config providersConfig = Config.empty();
173-
// MediaContext should be updated with config processing or during final build if not set.
174-
private MediaContext mediaContext;
174+
private MediaContext mediaContext = MediaContext.create();
175+
private MediaContext.Builder mediaContextBuilder;
175176
private ContentEncodingContext contentEncodingContext = ContentEncodingContext.create();
176177

177178
private boolean shutdownHook = true;
@@ -198,8 +199,17 @@ public WebServer build() {
198199
.build();
199200
}
200201
if (mediaContext == null) {
201-
mediaContext(MediaContext.create());
202+
if (mediaContextBuilder == null) {
203+
mediaContext = MediaContext.create();
204+
} else {
205+
mediaContext = mediaContextBuilder.build();
206+
}
207+
} else {
208+
if (mediaContextBuilder != null) {
209+
mediaContext = mediaContextBuilder.fallback(mediaContext).build();
210+
}
202211
}
212+
mediaContextBuilder = null;
203213

204214
return new LoomServer(this, configBuilder.build(), directHandlers.build());
205215
}
@@ -264,10 +274,15 @@ public Builder config(Config config) {
264274
.as(ContentEncodingContext::create)
265275
.ifPresent(this::contentEncodingContext);
266276
// Configure media support
267-
config.get("media-support")
268-
.as(MediaContext::create)
269-
// MediaContext always needs to be refreshed after config change
270-
.ifPresent(this::mediaContext);
277+
Config mediaSupportConfig = config.get("media-support");
278+
if (mediaSupportConfig.exists()) {
279+
// we are directly updating the builder, and we do not need to fallback to defaults
280+
// also configuration overrides any manual setup
281+
mediaContext = null;
282+
mediaContextBuilder = MediaContext.builder();
283+
mediaSupportConfig.ifExists(mediaContextBuilder::config);
284+
}
285+
271286
// Store providers config node for later usage.
272287
providersConfig = config.get("connection-providers");
273288
return this;
@@ -424,11 +439,35 @@ public boolean hasSocket(String socketName) {
424439
}
425440

426441
/**
427-
* Configure the default {@link MediaContext}.
428-
* This method discards all previously registered MediaContext.
442+
* Add an explicit media support to the list.
443+
* By default, all discovered media supports will be available to the server. Use this method only when
444+
* the media support is not discoverable by service loader, or when using explicit
445+
* {@link #mediaContext(io.helidon.nima.http.media.MediaContext)}.
446+
*
447+
* @param mediaSupport media support to add
448+
* @return updated builder
449+
*/
450+
public Builder addMediaSupport(MediaSupport mediaSupport) {
451+
Objects.requireNonNull(mediaSupport);
452+
if (mediaContextBuilder == null) {
453+
mediaContextBuilder = MediaContext.builder()
454+
.discoverServices(false);
455+
}
456+
457+
mediaContextBuilder.addMediaSupport(mediaSupport);
458+
return this;
459+
}
460+
461+
/**
462+
* Configure the {@link MediaContext}.
463+
* This method discards previously registered {@link io.helidon.nima.http.media.MediaContext}
464+
* and all previously registered {@link io.helidon.nima.http.media.MediaSupport}.
465+
* If an explicit media support is configured using {@link #addMediaSupport(io.helidon.nima.http.media.MediaSupport)},
466+
* this context will be used as a fallback for a new one created from configured values.
429467
*
430468
* @param mediaContext media context
431469
* @return updated instance of the builder
470+
* @see #addMediaSupport(io.helidon.nima.http.media.MediaSupport)
432471
*/
433472
public Builder mediaContext(MediaContext mediaContext) {
434473
Objects.requireNonNull(mediaContext);

nima/webserver/webserver/src/test/java/io/helidon/nima/webserver/WebServerConfigTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ void testMediaSupportFileConfigJson() throws IOException {
9292
Config config = Config.create();
9393
Config server = config.get("server2");
9494
WebServer.Builder wsBuilder = WebServer.builder().config(server);
95+
wsBuilder.build(); // triggers processing of media context
9596
MediaContext mediaContext = wsBuilder.mediaContext();
9697
assertThat(mediaContext, is(notNullValue()));
9798
WritableHeaders<?> writableHeaders = WritableHeaders.create();
@@ -120,6 +121,7 @@ void testMediaSupportFileConfigJson() throws IOException {
120121
void testMediaSupportFileConfigNoJson() throws IOException {
121122
Config config = Config.create();
122123
WebServer.Builder wsBuilder = WebServer.builder().config(config.get("server"));
124+
wsBuilder.build(); // trigger processing of media context
123125
MediaContext mediaContext = wsBuilder.mediaContext();
124126
assertThat(mediaContext, is(notNullValue()));
125127
WritableHeaders<?> writableHeaders = WritableHeaders.create();

0 commit comments

Comments
 (0)