Should I throw an EJBException to prevent Entity creation - jsf-2

I have the following code:
JSF Managed Bean:
#ManagedBean(name = "purchaseView")
#ViewScoped
public class PurchaseView implements Serializable {
#EJB
private PurchaseService service;
private Order order;
// Getter/Setters here
public void checkoutOrder() {
// .. some checks for null here, then call service
service.checkout(order);
}
}
Service:
#Stateless
public class BuyVoucherService {
#EJB
private OrderBean orderBean;
#EJB
private ProductBean productBean;
public boolean checkout(Order order) {
orderBean.create(order);
for(int i=0;i<order.getQuantity();i++) {
Product product = new Product();
if(someCondition) {
// don't save anything and
return false;
}
// .. some setter here
product.setOrder(order);
productBean.create(product);
}
return true;
}
The productBean and orderBean are simple JPA EJB with the EntityManager and CRUD operation (Generated by Netbeans..).
In the Service above, things are persisted in the database when the Service returns. In the case something is wrong (someCondition == TRUE above), if I return false the orderBean.save(order) will still persist the order in the database, and I don't want that.
Is throwing an EJBException and catching it in the ManagedBean the best option?

As you haven't specified any transaction attribute explicitly, it will be most probably Required, but depends on the server. Therefore both these methods will be within same transaction, so rolling back in a method will cascade the changes in another.
You can also try using Mandatory attribute for the 2nd method, it will ensure that it requires a transaction to proceed further, else will cause runtime exception.
#Resource
private EJBContext context;
try{
if(someCondition) {
throw SomeBusinessException("Failed, rolling back");
}
}catch(Exception e){
log(e.getMessage, e)
context.setRollbackOnly();
}
Else, you can throw system exception, that will force the container to rollback the changes being made.
if(someCondition)
throw SomeBusinessException("Failed, rolling back");
}catch(Exception e){
throw new EJBException (e.getMessage(), e);
}

Related

.Net Core: Custom scope for "Scoped" Dependency injection w.out. a controller

I have an application that does not recieve ordinary HTTP requests through a controller, instead it listens to and receives messages (AMQP protocol) in order to initiate it's logic flow.
My application may receive and handle more than 1 message at a time. I have an object that will be collecting information/data throughout the process, in several different services/classes, in order for me to use it at the end.
But I need the data to be seperated per message received, as a "Scoped" injection would seperate the injected instance from other HTTP requests.
My usecase is therefor very similar to how I would use a Scoped injected object in an ordinary API, but instead of a new HTTP request, I receive a message in my listeners.
Is there any way that I can create a custom scope, for every message received, either through some kind of configuration, or having the code create a new scope as the first thing in my Listener.MessageReceived(Message message) method?
Imagine a flow like this:
public class Listener {
ServiceClassA serviceClassA //injected in constructor
CustomLogger customLogger // (HAS TO BE SAME OBJECT INJECTED INTO ServiceClassA, ServiceClassB and Listener)
public void ReceiveMessage(Message message) {
using (var scope = CreateNewScope()) {
try {
serviceClassA.DoStuff();
} catch(Exception e) {
Console.Write(customLogger.GetLogs())
}
}
}
}
public class ServiceClassA {
ServiceClassB serviceClassB //injected in constructor
CustomLogger customLogger //(HAS TO BE SAME OBJECT INJECTED INTO ServiceClassA, ServiceClassB and Listener)
public void DoStuff() {
customLogger = ResolveCustomLogger(); // how do I make sure I can get/resolve the same object as in Listener (without having to pass parameters)
var data = // does stuff
customLogger.Log(data);
serviceClassB.DoStuff();
}
}
public class ServiceClassB {
CustomLogger customLogger //(HAS TO BE SAME OBJECT INJECTED INTO ServiceClassA, ServiceClassB and Listener)
public void DoStuff() {
customLogger = ResolveCustomLogger(); // how do I make sure I can get/resolve the same object as in Listener (without having to pass parameters)
var data = // does other stuff
customLogger.Log(data);
}
}
My CustomLogger may not only be used 1 or 2 service layers down, there might be many layers, and I might only want to use the CustomLogger in the bottom on, yet I want it accessible in the top level afterwards, to retrieve the data stored in it.
Thank you very much.
You can inject a ServiceScopyFactory in the class that reacts to messages from the queue, then for each message it receives it can create a scope, from which it requests a MessageHandler dependency.
The code sample below does exactly this (and it also deals with sessions on the queue, but that should make no difference for creating the scope).
public class SessionHandler : ISessionHandler
{
public readonly string SessionId;
private readonly ILogger<SessionHandler> Logger;
private readonly IServiceScopeFactory ServiceScopeFactory;
readonly SessionState SessionState;
public SessionHandler(
ILogger<SessionHandler> logger,
IServiceScopeFactory serviceScopeFactory,
string sessionId)
{
Logger = logger;
ServiceScopeFactory = serviceScopeFactory;
SessionId = sessionId
SessionState = new SessionState();
}
public async Task HandleMessage(IMessageSession session, Message message, CancellationToken cancellationToken)
{
Logger.LogInformation($"Message of {message.Body.Length} bytes received.");
// Deserialize message
bool deserializationSuccess = TryDeserializeMessageBody(message.Body, out var incomingMessage);
if (!deserializationSuccess)
throw new NotImplementedException(); // Move to deadletter queue?
// Dispatch message
bool handlingSuccess = await HandleMessageWithScopedHandler(incomingMessage, cancellationToken);
if (!handlingSuccess)
throw new NotImplementedException(); // Move to deadletter queue?
}
/// <summary>
/// Instantiate a message handler with a service scope that lasts until the message handling is done.
/// </summary>
private async Task<bool> HandleMessageWithScopedHandler(IncomingMessage incomingMessage, CancellationToken cancellationToken)
{
try
{
using IServiceScope messageHandlerScope = ServiceScopeFactory.CreateScope();
var messageHandlerFactory = messageHandlerScope.ServiceProvider.GetRequiredService<IMessageHandlerFactory>();
var messageHandler = messageHandlerFactory.Create(SessionState);
await messageHandler.HandleMessage(incomingMessage, cancellationToken);
return true;
}
catch (Exception exception)
{
Logger.LogError(exception, $"An exception occurred when handling a message: {exception.Message}.");
return false;
}
}
private bool TryDeserializeMessageBody(byte[] body, out IncomingMessage? incomingMessage)
{
incomingMessage = null;
try
{
incomingMessage = IncomingMessage.Deserialize(body);
return true;
}
catch (MessageDeserializationException exception)
{
Logger.LogError(exception, exception.Message);
}
return false;
}
}
Now whenever a MessageHandlerFactory is instantiated (which happens for each message received from the queue), any scoped dependencies requested by the factory will live until the MessageHandler.HandleMessage() task finishes.
I created a message handler factory so that the SessionHandler could pass non-DI-service arguments to the constructor of the MessageHandler (the SessionState object in this case) in addition to the DI-services. It is the factory who requests the (scoped) dependencies and passes them to the MessageHandler. If you are not using sessions then you might not need the factory, and you can instead fetch a MessageHandler from the scope directly.

StackOverflowException in spring-data-jpa app with spring-security AuditorAware

I have a really nasty StackOverflowException in my spring backend, that I need help with. This is not going to be solved easily. I really hope to find some help here.
Most parts of my backend work. I can query my REST interface for models, they are nicely returned by spring-hateoas, GET, PUT and POST operations work. But one exception: When I try to update an existing DelegationModel, then I run into an endless StackOverflowException.
Here is my DelegetionModel.java class. Please mark, that delegation model actually doesn't have any property annotated with #CreatedBy!
#Entity
#Data
#NoArgsConstructor
#RequiredArgsConstructor(suppressConstructorProperties = true) //BUGFIX: https://jira.spring.io/browse/DATAREST-884
#EntityListeners(AuditingEntityListener.class) // this is necessary so that UpdatedAt and CreatedAt are handled.
#Table(name = "delegations")
public class DelegationModel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
/** Area that this delegation is in */
#NonNull
#NotNull
#ManyToOne
public AreaModel area;
/** reference to delegee that delegated his vote */
#NonNull
#NotNull
#ManyToOne
public UserModel fromUser;
/** reference to proxy that receives the delegation */
#NonNull
#NotNull
#ManyToOne
public UserModel toProxy;
#CreatedDate
#NotNull
public Date createdAt = new Date();
#LastModifiedDate
#NotNull
public Date updatedAt = new Date();
}
As described in the Spring-data-jpa doc I implemented the necessary AuditorAware interface, which loads the UserModel from the SQL DB. I would have expected that this AuditorAware interface is only called for models that have a field annotated with #CreatedBy.
#Component
public class LiquidoAuditorAware implements AuditorAware<UserModel> {
Logger log = LoggerFactory.getLogger(this.getClass()); // Simple Logging Facade 4 Java
#Autowired
UserRepo userRepo;
#Override
public UserModel getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
log.warn("Cannot getCurrentAuditor. No one is currently authenticated");
return null;
}
User principal = (org.springframework.security.core.userdetails.User) authentication.getPrincipal();
UserModel currentlyLoggedInUser = userRepo.findByEmail(principal.getUsername()); // <<<<======= (!)
return currentlyLoggedInUser;
} catch (Exception e) {
log.error("Cannot getCurrentAuditor: "+e);
return null;
}
}
}
Now I update a DelegationModel in my UserRestController. The functional "Scrum User Story" here is:
As a user I want to be able to store a delegation so that I can forward my right to vote to my proxy.
#RestController
#RequestMapping("/liquido/v2/users")
public class UserRestController {
[...]
#RequestMapping(value = "/saveProxy", method = PUT, consumes="application/json")
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody String saveProxy(
#RequestBody Resource<DelegationModel> delegationResource,
//PersistentEntityResourceAssembler resourceAssembler,
Principal principal) throws BindException
{
[...]
DelegationModel result = delegationRepo.save(existingDelegation);
[...]
}
[...]
}
For some reason, that I cannot see, this actualy calls the AuditorAware implementation above. The problem is now, that my LqiuidoAuditorAware implementation is called again and again in and endless loop. It seems that the query for the UserModel inside LiquidoAuditorAware.java calls the LiquidoAuditorAware again. (Which is unusual, because that is only a read operation from the DB.)
Here is the full ThreadDump as a Gist
All the code can by found in this github repo
I'd really apriciate any help here. I am searching in the dark :-)
The reason for the behavior you see is that the AuditorAware implementation is called from within a JPA #PrePersist/#PreUpdate callback. You now issue a query by calling findByEmail(…), which triggers the dirty-detection again, which in turn causes the flushing to be triggered and thus the invocation of the callbacks.
The recommended workaround is to keep an instance of the UserModel inside the Spring Security User implementation (by looking it up when the UserDetailsService looks up the instance on authentication), so that you don't need an extra database query.
Another (less recommended) workaround could be to inject an EntityManager into the AuditorAware implementation, call setFlushMode(FlushModeType.COMMIT) before the query execution and reset it to FlushModeType.AUTO after that, so that the flush will not be triggered for the query execution.

Configure/register depdency injection scoped service from within the scope

I have a stateless service in Azure Service Fabric, and I'm using Microsoft.Extensions.DependencyInjection, although the same issue exists for any other DI frameworks. In my Program.cs, I create a ServiceCollection, add all (but one) of my registrations, create the service provider, and pass it to my service's constructor. Any service method with external entry will create a new service scope and call the main business logic class. The issue is that one of the classes I want to have scoped lifetime needs a value that is an input parameter on the request itself. Here's a code snippet of what I would like to achieve.
internal sealed class MyService : StatelessService, IMyService
{
private IServiceProvider _serviceProvider;
private IServiceScopeFactory _scopeFactory;
public MyService(StatelessServiceContext context, IServiceProvider serviceProvider)
: base(context)
{
_serviceProvider = serviceProvider;
_scopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
}
public async Task<MyResponse> ProcessAsync(MyRequest request, string correlationId, CancellationToken cancellationToken)
{
using (var scope = _scopeFactory.CreateScope())
{
var requestContext = new RequestContext(correlationId);
//IServiceCollection serviceCollection = ??;
//serviceCollection.AddScoped<RequestContext>(di => requestContext);
var businessLogic = scope.ServiceProvider.GetRequiredService<BusinessLogic>();
return await businessLogic.ProcessAsync(request, cancellationToken);
}
}
}
The cancellation token is already passed around everywhere, including to classes that don't use it directly, just so it can be passed to dependencies that do use it, and I want to avoid doing the same with the request context.
The same issue exists in my MVC APIs. I can create middle-ware which will extract the correlation id from the HTTP headers, so the API controller doesn't need to deal with it like my service fabric service does. One way I can make it work is by giving RequestContext a default constructor, and have a mutable correlation id. However, it's absolutely critical that the correlation id doesn't get changed during a request, so I'd really like the safety of having get-only property on the context class.
My best idea at the moment is to have a scoped RequestContextFactory which has a SetCorrelationId method, and the RequestContext registration simply calls the factory to get an instance. The factory can throw an exception if a new instance is requested before the id is set, to ensure no id-less contexts are created, but it doesn't feel like a good solution.
How can I cleanly register read-only objects with a dependency injection framework, where the value depends on the incoming request?
I only had the idea for a RequestContextFactory as I was writing the original question, and I finally made time to test the idea out. It actually was less code than I expected, and worked well, so this will be my go-to solution now. But, the name factory is wrong. I'm not sure what to call it though.
First, define the context and factory classes. I even added some validation checks into the factory to ensure it worked the way I expect:
public class RequestContext
{
public RequestContext(string correlationId)
{
CorrelationId = correlationId;
}
public string CorrelationId { get; }
}
public class RequestContextFactory
{
private RequestContext _requestContext;
private bool _used = false;
public void SetContext(RequestContext requestContext)
{
if (_requestContext != null || requestContext == null)
{
throw new InvalidOperationException();
}
_requestContext = requestContext;
}
public RequestContext GetContext()
{
if (_used || _requestContext == null)
{
throw new InvalidOperationException();
}
_used = true;
return _requestContext;
}
}
Then, add registrations to your DI container:
services.AddScoped<RequestContextFactory>();
services.AddScoped<RequestContext>(di => di.GetRequiredService<RequestContextFactory>().GetContext());
Finally, the Service Fabric service method looks something like this
public async Task<MyResponse> ProcessAsync(MyRequest request, string correlationId, CancellationToken cancellationToken)
{
using (var scope = _scopeFactory.CreateScope())
{
var requestContext = new RequestContext(correlationId);
var requestContextFactory = scope.ServiceProvider.GetRequiredService<RequestContextFactory>();
requestContextFactory.SetContext(requestContext);
var businessLogic = scope.ServiceProvider.GetRequiredService<BusinessLogic>();
return await businessLogic.ProcessAsync(request, cancellationToken);
}
}
Kestrel middleware could look something like this
public async Task Invoke(HttpContext httpContext)
{
RequestContext requestContext = new RequestContext(Guid.NewGuid().ToString());
var factory = httpContext.RequestServices.GetRequiredService<RequestContextFactory>();
factory.SetContext(requestContext);
httpContext.Response.Headers["X-CorrelationId"] = requestContext.CorrelationId;
await _next(httpContext);
}
Then just do the normal thing and add a RequestContext parameter to the constructor of any class that needs to get the correlation id (or any other info you put in the request context)

Spring Data Neo4 - BeforeSaveEvent deprecated

In my Spring Data Neo4j 4 project - BeforeSaveEvent class is deprecated.
Also, previously I used a following code in order to setup created/updated date for my entities:
#EventListener
public void handleBeforeSaveEvent(BeforeSaveEvent event) {
Object entity = event.getEntity();
if (entity instanceof BaseEntity) {
BaseEntity baseEntity = (BaseEntity) entity;
if (baseEntity.getCreateDate() == null) {
baseEntity.setCreateDate(new Date());
} else {
baseEntity.setUpdateDate(new Date());
}
}
}
but right now this listener is not invoked.
Is there any replacement for this logic in Neo4j 4 ? I'll really appreciate an example. Thanks
UPDATED
The configuration described below is working but some of my tests are fail because of NULL dates on a previously saved entities.. something is still wrong..
After clarification found a reason of this issue and waiting for this bugfix Modifications during a onPreSave() event do not persist to the database
#Configuration
#EnableExperimentalNeo4jRepositories(basePackages = "com.example")
#EnableTransactionManagement
public class Neo4jTestConfig {
#Bean
public Neo4jTransactionManager transactionManager() throws Exception {
return new Neo4jTransactionManager(sessionFactory());
}
#Bean
public SessionFactory sessionFactory() {
return new SessionFactory("com.example") {
#Override
public Session openSession() {
Session session = super.openSession();
session.register(new EventListenerAdapter() {
#Override
public void onPreSave(Event event) {
Object eventObject = event.getObject();
if(eventObject instanceof BaseEntity) {
BaseEntity baseEntity = (BaseEntity) eventObject;
if (baseEntity.getCreateDate() == null) {
baseEntity.setCreateDate(new Date());
} else {
baseEntity.setUpdateDate(new Date());
}
}
}
});
return session;
}
};
}
}
You must be using Spring Data Neo4j (SDN) 4.2.0.M1. This has not been officially released yet but you are free to test it while it is undergoing the Spring Data Release process.
The event code in SDN has been deprecated in favour of a variety of mechanisms. Number one is that Spring Data now support Transaction aware event listeners. You can check out how to implement those here.
Number two is that you can now autowire the Neo4j OGM Session into your application and take advantage of it's event capabilities (see the register() method).
Finally you are able to marry the two concepts up together and get OGM generated events fired through Spring!
Documentation will come as we continue the release but for now feel free to play with it yourself.

MVC - Simple Injector and Attribute calling the Context (EF) Throwing exceptions

If I start my application and let it settle, it works great.
However, when I debug my application and if I close the browser tab before it initializes anything and then call another like localhost:81/Home/Test, it throws an exception on retrieving data from DB (EF).
This exception occurs during a call to a Filter CultureResolver which then calls LanguageService. Inside LanguageService there is a call to the DB to retrieve all the available languages.
I got many different exceptions, like:
The context cannot be used while the model is being created. This
exception may be thrown if the context is used inside the
OnModelCreating method or if the same context instance is accessed by
multiple threads concurrently. Note that instance members of
DbContext and related classes are not guaranteed to be thread safe.
Object reference not set to an instance of an object.
The underlying provider failed on Open.
Those exceptions occur all in the same query, it depends on how much time I left the first tab running.
So it seems it's something like Thread-Unsafe code or this query trying to get items before the Context is initialized.
I've the following:
SimpleInjectorInitializer.cs
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, container);
}
private static void InitializeContainer(Container container)
{
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
/* Bindings... */
container.RegisterPerWebRequest<IAjaxMessagesFilter, AjaxMessagesFilter>();
container.RegisterPerWebRequest<ICustomErrorHandlerFilter, CustomErrorHandlerFilter>();
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
}
}
FilterConfig.cs
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
filters.Add(container.GetInstance<ICultureInitializerFilter>());
filters.Add(container.GetInstance<ICustomErrorHandlerFilter>());
filters.Add(container.GetInstance<IAjaxMessagesFilter>());
}
}
CultureResolver.cs
public class CultureResolver : ICultureResolver
{
ILanguageService Service;
public CultureResolver(ILanguageService Service)
{
this.Service = Service;
}
public string Resolve(string CultureCode)
{
// Get the culture by name or code (pt / pt-pt)
ILanguageViewModel language = Service.GetByNameOrCode(CultureCode);
if (language == null)
{
// Get the default language
language = Service.GetDefault();
}
return language.Code;
}
}
LanguageService.cs
public class LanguageService : ILanguageService
{
IMembership membership;
ChatContext context;
ILanguageConverter converter;
public LanguageService(
ChatContext context,
IMembership membership,
ILanguageConverter converter
)
{
this.membership = membership;
this.context = context;
this.converter = converter;
}
public virtual ILanguageViewModel GetByNameOrCode(string Text)
{
string lowerText = Text.ToLower();
string lowerSmallCode = "";
int lowerTextHiphen = lowerText.IndexOf('-');
if (lowerTextHiphen > 0)
lowerSmallCode = lowerText.Substring(0, lowerTextHiphen);
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);
return converter.Convert(item);
}
public virtual ILanguageViewModel GetDefault()
{
Language item = this.context
.Languages
.FirstOrDefault(x => x.Default);
return converter.Convert(item);
}
}
This is the query that is giving me the exceptions
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);
Global filters in MVC and Web API are singletons. There is only one instance of such filter during the lifetime of your application. This becomes obvious when you look at the following code:
filters.Add(container.GetInstance<ICultureInitializerFilter>());
Here you resolve the filter once from the container and store it for the lifetime of the container.
You however, have registered this type as Scoped using:
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
You are effectively saying that there should be one instance per web request, most likely because that class depends on a DbContext, which isn't thread-safe.
To allow your filters to have dependencies, you should either make them humble objects, or wrap them in a humble object that can call them. For instance, you can create the following action filter:
public sealed class GlobalActionFilter<TActionFilter> : IActionFilter
where TActionFilter : class, IActionFilter
{
private readonly Container container;
public GlobalActionFilter(Container container) { this.container = container; }
public void OnActionExecuted(ActionExecutedContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuted(filterContext);
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuting(filterContext);
}
}
This class allows you to add your global filters as follows:
filters.Add(new GlobalActionFilter<ICultureInitializerFilter>(container));
filters.Add(new GlobalActionFilter<ICustomErrorHandlerFilter>(container));
filters.Add(new GlobalActionFilter<IAjaxMessagesFilter>(container));
The GlovalActionFilter<T> will callback into the container to resolve the supplied type every time it is called. This prevents the dependency from becoming captive which prevents the problems you are having.

Resources