Skip to content

Commit

Permalink
Make Http request and response headers available to repositories and …
Browse files Browse the repository at this point in the history
…modules #94

HttpRequestContextAware introduced. Instances loaded by ServiceDiscovery are checked for this interfaced and setup accordingly.
  • Loading branch information
remmeier committed Sep 2, 2017
1 parent 0aa42b7 commit 97e8817
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 15 deletions.
42 changes: 27 additions & 15 deletions crnk-core/src/main/java/io/crnk/core/boot/CrnkBoot.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package io.crnk.core.boot;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import io.crnk.core.engine.error.JsonApiExceptionMapper;
import io.crnk.core.engine.filter.DocumentFilter;
import io.crnk.core.engine.http.HttpRequestContextAware;
import io.crnk.core.engine.information.resource.ResourceFieldInformationProvider;
import io.crnk.core.engine.information.resource.ResourceFieldNameTransformer;
import io.crnk.core.engine.internal.dispatcher.ControllerRegistry;
Expand All @@ -26,11 +22,7 @@
import io.crnk.core.engine.properties.NullPropertiesProvider;
import io.crnk.core.engine.properties.PropertiesProvider;
import io.crnk.core.engine.query.QueryAdapterBuilder;
import io.crnk.core.engine.registry.DefaultResourceRegistryPart;
import io.crnk.core.engine.registry.HierarchicalResourceRegistryPart;
import io.crnk.core.engine.registry.RegistryEntry;
import io.crnk.core.engine.registry.ResourceRegistry;
import io.crnk.core.engine.registry.ResourceRegistryPart;
import io.crnk.core.engine.registry.*;
import io.crnk.core.engine.url.ConstantServiceUrlProvider;
import io.crnk.core.engine.url.ServiceUrlProvider;
import io.crnk.core.module.Module;
Expand Down Expand Up @@ -58,6 +50,10 @@
import io.crnk.legacy.repository.information.DefaultResourceRepositoryInformationBuilder;
import net.jodah.typetools.TypeResolver;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* Facilitates the startup of Crnk in various environments (Spring, CDI,
* JAX-RS, etc.).
Expand Down Expand Up @@ -132,6 +128,7 @@ public void setServiceLocator(JsonServiceLocator serviceLocator) {
*/
public void addModule(Module module) {
checkNotConfiguredYet();
setupInstance(module);
moduleRegistry.addModule(module);
}

Expand Down Expand Up @@ -268,16 +265,16 @@ public void setupModule(ModuleContext context) {
module.addRepositoryInformationBuilder(new DefaultRelationshipRepositoryInformationBuilder());

AnnotationResourceInformationBuilder resourceInformationBuilder =
new AnnotationResourceInformationBuilder(resourceFieldNameTransformer, getResourceFieldInformationProviders());
new AnnotationResourceInformationBuilder(resourceFieldNameTransformer, getResourceFieldInformationProviders());
module.addResourceInformationBuilder(resourceInformationBuilder);

for (JsonApiExceptionMapper<?> exceptionMapper : serviceDiscovery.getInstancesByType(JsonApiExceptionMapper.class)) {
for (JsonApiExceptionMapper<?> exceptionMapper : getInstancesByType(JsonApiExceptionMapper.class)) {
module.addExceptionMapper(exceptionMapper);
}
for (DocumentFilter filter : serviceDiscovery.getInstancesByType(DocumentFilter.class)) {
for (DocumentFilter filter : getInstancesByType(DocumentFilter.class)) {
module.addFilter(filter);
}
for (Object repository : serviceDiscovery.getInstancesByType(Repository.class)) {
for (Object repository : getInstancesByType(Repository.class)) {
setupRepository(module, repository);
}
for (Object repository : serviceDiscovery.getInstancesByAnnotation(JsonApiResourceRepository.class)) {
Expand All @@ -295,6 +292,21 @@ public void setupModule(ModuleContext context) {
moduleRegistry.setPropertiesProvider(propertiesProvider);
}

private <T> List<T> getInstancesByType(Class<T> clazz) {
List<T> instancesByType = serviceDiscovery.getInstancesByType(clazz);
for (T instance : instancesByType) {
setupInstance(instance);
}
return instancesByType;
}

private <T> void setupInstance(T instance) {
if (instance instanceof HttpRequestContextAware) {
HttpRequestContextAware aware = (HttpRequestContextAware) instance;
aware.setHttpRequestContextProvider(moduleRegistry.getHttpRequestContextProvider());
}
}

private void setupRepository(SimpleModule module, Object repository) {
if (repository instanceof ResourceRepository) {
ResourceRepository resRepository = (ResourceRepository) repository;
Expand All @@ -319,7 +331,7 @@ private void setupRepository(SimpleModule module, Object repository) {
}

private void addModules() {
List<Module> modules = serviceDiscovery.getInstancesByType(Module.class);
List<Module> modules = getInstancesByType(Module.class);
for (Module module : modules) {
moduleRegistry.addModule(module);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.crnk.core.engine.http;

/**
* Can be implemented by repositories to get access to request parameters.
*/
public interface HttpRequestContextAware {

void setHttpRequestContextProvider(HttpRequestContextProvider requestContextProvider);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.crnk.core.engine.http;

import io.crnk.core.boot.CrnkBoot;
import io.crnk.core.engine.url.ConstantServiceUrlProvider;
import io.crnk.core.module.Module;
import io.crnk.core.module.discovery.ReflectionsServiceDiscovery;
import io.crnk.core.resource.registry.ResourceRegistryBuilderTest;
import org.junit.Test;
import org.mockito.Mockito;

import java.io.IOException;

public class HttpRequestContextAwareTest {

interface HttTestModule extends Module, HttpRequestContextAware {

}

@Test
public void check() throws IOException {
HttTestModule testModule = Mockito.mock(HttTestModule.class);

CrnkBoot boot = new CrnkBoot();
boot.setServiceUrlProvider(new ConstantServiceUrlProvider("http://localhost:8080"));
boot.setServiceDiscovery(new ReflectionsServiceDiscovery(ResourceRegistryBuilderTest.TEST_MODELS_PACKAGE));
boot.addModule(testModule);
boot.boot();

Mockito.verify(testModule, Mockito.times(1)).setHttpRequestContextProvider(Mockito.any(HttpRequestContextProvider.class));
}
}
14 changes: 14 additions & 0 deletions crnk-documentation/src/docs/asciidoc/module_development.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ query those `ResourceFilter` and only display information about resources and fi
of the current re quest. The `ResourceFilterDirectory` makes use of per-request caching as the information
may be accessed repeatedly for a request.
## Access to HTTP layer
`HttpRequestContext` resp. `HttpRequestContextProvider` provides access to the HTTP requests. Most
notably to get and set HTTP request and response headers. In many cases, the underlying
implementation like JAXRS or Servlet provides that access as well. With `HttpRequestContext`
there is an implementation that is independent of that implementation. As such it is well suited
for module development, in particular for request filtering. A typical use case is to set and
access security headers.
`HttpRequestContextProvider.getRequestContext` returns the request context for the currently
active request. Modules have access to `HttpRequestContextProvider` trough the `ModuleContext`.
Repositories, filters and modules can implement `HttpRequestContextAware` to get
access to `HttpRequestContextProvider`.
## Integrate third-party data stores
Expand Down

0 comments on commit 97e8817

Please sign in to comment.