set database pulled application constants on startup - servlets

I have a lot of dropdown menus in my application. The contents of these dropdown menus is read from the database.
Currently, to avoid pulling these values back every-time I want to use them, I pull them back once when I first need them and store them in the session after that.
This is not good. I do want to be storing them in the session as there are a number of them, and I think it's a bit, well, clunky. I would like to ideally (assuming you don't disagree), store these 'constants' (they aren't traditional constants, but they won't change for the duration of the deployment), in the application scope, so they need only be pulled back from the database once per deployment.
What I'm wondering is, what is the way to store these dropdown values in the application context at startup?

There is an interface by the name of ServletContextListener which provides a hook into the initialization of your servlet context. The ServletContext is your application's context, ie. its configuration.
One way to do what you are describing is to implement this interface and register the ServletContextListener either in web.xml or by annotating the class with #WebListener.
In the contextInitialized() method, you would pull the constants, set them up in any way you needed to and then put them in the ServletContext as attributes
#WebListener
public static class MyListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
int someConstant = 42;
context.setAttribute("myConstant", someConstant);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
...
}
}
You can then access these constants anywhere you have access to the ServletContext.
In a Servlet or Filter, you can get it from the ServletRequest
HttpServletRequest request = ....;
request.getServletContext();
You also have access to it from the init() methods of Servlet and Filter if you want to add more attributes there.

Related

How to keep a statefull bean clean or reset during a #QuarkusTest?

I test a statefull bean with a #QuarkusTest. It keeps a certain state. Obviously, I would like to have a fresh bean for every test. At the moment, each test might modify he current state, which is the effective for a oncoming test. This is highly undersireable and breaks my tests.
Is there a way to force a new bean clean bean getting injected for every test when running a #QuarkusTest?
Eg. A very basic subscription service, which holds the current subscription to avoid double subscriptions:
#ApplicationScoped
public class SubscriptionService {
#Inject
DeviceClient deviceClient;
private final Set<String> subscribedDevices = new HashSet<>();
public void subscribe(String deviceId, Consumer<RadarFrame> consumer){
if(subscriptions.contains(deviceId)){
return;
}
deviceClient.subscribe(deviceId, consumer);
subscriptions.add(deviceId);
}
public void unsubscribe(String deviceId, Consumer<RadarFrame> consumer){
deviceClient.unsubscribe(deviceId);
subscriptions.remove(deviceId);
}
}
I could manually unsubscribe the device after each test, which is a bad small as I use potention untested implemented logic for setup/teardown. It would be nice if a injected bean could be reinitialized before each test on a #QuarkusTest.
Or did I miss another clean option?
#ApplicationScoped beans will be there for the entire life of the container.
The recommended way to do this is to create a reset() method in the bean to later be called in tests. With JUnit 5 this would be something like:
#AfterEach
void tearDown() {
subscriptionService.reset();
}
You can make that method package friendly to limit it's usage.

How to use ResourceProcessorHandlerMethodReturnValueHandler in a spring-hateos project

When using spring-data-rest there is a post processing of Resource classes returned from Controllers (e.g. RepositoryRestControllers). The proper ResourceProcessor is called in the post processing.
The class responsible for this is ResourceProcessorHandlerMethodReturnValueHandler which is part of spring-hateoas.
I now have a project that only uses spring-hateoas and I wonder how to configure ResourceProcessorHandlerMethodReturnValueHandler in such a scenario. It looks like the auto configuration part of it still resides in spring-data-rest.
Any hints on how to enable ResourceProcessorHandlerMethodReturnValueHandler in a spring-hateoas context?
I've been looking at this recently too, and documentation on how to achieve this is non-existent. If you create a bean of type ResourceProcessorInvokingHandlerAdapter, you seem to lose the the auto-configured RequestMappingHandlerAdapter and all its features. As such, I wanted to avoid using this bean or losing the WebMvcAutoConfiguration, since all I really wanted was the ResourceProcessorHandlerMethodReturnValueHandler.
You can't just add a ResourceProcessorHandlerMethodReturnValueHandler via WebMvcConfigurer.addReturnValueHandlers, because what we need to do is actually override the entire list, as is what happens in ResourceProcessorInvokingHandlerAdapter.afterPropertiesSet:
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Retrieve actual handlers to use as delegate
HandlerMethodReturnValueHandlerComposite oldHandlers = getReturnValueHandlersComposite();
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
// Configure the new handler to be used
this.setReturnValueHandlers(newHandlers);
}
So, without a better solution available, I added a BeanPostProcessor to handle setting the List of handlers on an existing RequestMappingHandlerAdapter:
#Component
#RequiredArgsConstructor
#ConditionalOnBean(ResourceProcessor.class)
public class ResourceProcessorHandlerMethodReturnValueHandlerConfigurer implements BeanPostProcessor {
private final Collection<ResourceProcessor<?>> resourceProcessors;
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodReturnValueHandler> handlers =
requestMappingHandlerAdapter.getReturnValueHandlers();
HandlerMethodReturnValueHandlerComposite delegate =
handlers instanceof HandlerMethodReturnValueHandlerComposite ?
(HandlerMethodReturnValueHandlerComposite) handlers :
new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
requestMappingHandlerAdapter.setReturnValueHandlers(Arrays.asList(
new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors))));
return requestMappingHandlerAdapter;
}
else return bean;
}
}
This has seemed to work so far...

Passing application context to JSR 303 ConstraintValidator

Some of the JSR-3validation I want to do is context sensitive.
For example, my web application has a "year" context for each request. When persisting a new bean, I want to be able to constrain the year property to be within year of the current request context.
#InCurrentContextYear
private LocalDate activationDate;
The current year is contained in a request object that I want to pass (in some way) into the constraint validator. For example:
public class InCurrentContextYearValidator
implements ConstraintValidator<InCurrentContextYear, LocalDate>{
#Override
public void initialize(InCurrentContextYear constraintAnnotation) {}
#Override
public boolean isValid(
LocalDate value,
ConstraintValidatorContext context,
Request request) {
return DateUtil.isInRequestYear(value, request)
}
}
Now I could do this with thread-local storage, but I'm wondering if there's a better way.
I do recognize that this is getting somewhat outside the domain of "bean validation" but it seems like using annotations for such things is a defensible approach. Annotations allow me to keep my beans as POJOs, and service as a nice way to document the rules of the properties.
So why should I need to have an entirely separate mechanism to do essentially the same thing as bean validation?

How to pass global variable to a referenced assembly?

How to pass global variable to a referenced assembly?
I am modifying an asp.net app. It is required to log all Employee (the current user of the website) actions like saving a new customer or update invoice data. The UI layer is calling a referenced assembly BLL.dll.
I want to pass current Emplyee to the referenced assembly. The passed Employee should be shared accross all static methods in that dll. It should be thread safe because the Employee can be changed accross requests.
I can't expose static field in the BLL because the Employee is stored in session state.
I need something not static, Global, accessible by both assemblies (UI layer and BLL.dll), and thread safe.
I am thinking about using some variable stored in current thread object. but I don't know what exactly I should do??
Any workarrounds ??
Thanks
Basically you need something in your BLL that can get the reference. You can use a strategy pattern with an interface.
// IN BLL.dll
public interface IEmployeeContextImplementation
{
Employee Current { get; }
}
public static EmployeeContext
{
private static readonly object ImplementationLock = new object();
private static IEmployeeContextImplementation Implementation;
public static void SetImplementation(IEmployeeContextImplementation impl)
{
lock(ImplementationLock)
{
Implementation = impl;
}
}
public static Employee Current { get { return Implementation.Current; }
}
Then in your web app, implement IEmployeeContextImplementation with the session state and call SetImplementation only once in application start.
However, Session state is only good enough for within the context of a request. If you need it to go on a different thread, you will have to explicitly pass it to a different thread.

ASP.NET - Create custom context object?

How do I create a globally accessible Context object similar to the HttpContext object?
I want to create a custom class library which I want to reference from a website project. In the website project I want to be able to call the following globally:
ClassLibraryName.Context
I cannot create a global property directly in my classlibrary, so how should this be implemented? (I've seen other applications/products use this approach, one of which is Sitecore which has a custom Sitecore.Context object available)
Edit
Might this be a 'valid' solution?
namespace MyLibrary
{
public class Context
{
public static object ContextualObject
{
get;
set;
}
}
}
Yes, this is not hard to implement, if you always run this class in the context of an ASP.NET application, use this approach:
namespace MyLibrary
{
public class Context
{
public static object ContextualObject
{
get
{
var ctx = System.Web.HttpContext.Current.Items[typeof(Context)];
if (ctx == null)
{
ctx = new Context();
System.Web.HttpContext.Current.Items.Add(typeof(Context), ctx);
}
return ctx;
}
set { System.Web.HttpContext.Current.Items[typeof(Context)] = ctx; }
}
}
}
Essentially wrapping the existing HTTP context to provide your own service. This approach also doesn't store the object while the app lives, it only creates it for the current context, and when that response ends, it will die, and be regenerated during the next lifecycle. If that is not OK, store a static reference to context.
I've used this approach similarly in a class library I have at http://nucleo.codeplex.com, it works well.
HTH.
It depends on the lifetime you want the Context object to have. If you want all clients to use the same context, you can go with a singleton implementation.
If you want the context to be unique for each thread or http request you have to use a per request/thread implementation. One way to implement a per http request implementation would be to have a HttpModule create the object at every BeginRequest event and stick it in the HttpContext Items collection.
public static object ContextualObject
{
get { return HttpContext.Current.Items["MyContext"];}
}
You could create an instance of the object on Session_Start in the Global.asax.

Resources