I have a osgi component which works with JCR (for example, CRUD).
#Component
#Service
public class SomeServiceImpl implements SomeService {
#Reference
private ResourceResolverFactory resourceResolverFactory;
private ResourceResolver resourceResolver;
#Activate
private void init() {
resourceResolver = resourceResolverFactory.getServiceResourceResolver(
Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "myService"));
}
#Override
public void serve() {
//does something with resourceResolver
}
#Deactivate
private void dispose() {
resourceResolver.close();
}
}
It creates new instance of resourceResolver and keeps it as long as this service is alive. From time to time this service is invoked outside.
My questions are:
Is it correct approach where I once create resourceResolver and reuse it? Is it constantly?
Do I have guarantees that underlying session will not be expired?
By the way How long resourceResolver and their session lives and where can I see it?
What about concurrency? Imagine this service is invoked from serveral places parallely, Does Jackrabbit guarantee me consistency?
#Component
#Service
public class SomeServiceImpl implements SomeService {
#Reference
private SlingRepository slingRepository;
private Session session;
#Activate
private void init() {
session = slingRepository.login();
}
#Override
public void serve() {
//does something with session
}
#Deactivate
private void dispose() {
session.logout();
}
}
The same questions for another service (with session implementation).
It will be nice to see some proofs if it's possible. Maybe docs...
Thanks.
Is it correct approach where I once create resourceResolver and reuse it? Is it constantly?
No, it is not. It is perfect example of bad practice. Creation of resourceResolver is lightweight you can create as many as you need.
Note: you have to always close resourceResolver after usage but be careful and don't close it to early.
Do I have guarantees that underlying session will not be expired?
No you don't. AEM is collecting unclosed sessions after some time.
By the way How long resourceResolver and their session lives and where can I see it?
This session will became invalid after first concurrent write to the same resource. IRL big amount of changes even without conflict can fail on save.
What about concurrency? Imagine this service is invoked from serveral places parallely, Does Jackrabbit guarantee me consistency?
JCR session is supporting concurrency in scope of one session. Main assumption that will always create new session per update request.
The same questions for another service (with session implementation).
ResourceResolver is working over the Session it is just higher level of API.
Related
I have some data objects that are common across a Spring boot application - one is the logged in employee object and other is a category. I have created a #Component class which contains these are static variables. This way I do not even have to autowire them. They can be used directly like CurrentContext.employee in controllers.
#Component
public final class CurrentContext {
public static Category currentCategory;
public static Employee employee;
#Autowired
private CategoryService categoryService;
#Autowired
private EmployeeService employeeService;
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
currentCategory = categoryService.getCategory();
}
#EventListener
public void onLoginSuccess(InteractiveAuthenticationSuccessEvent event) {
employee = employeeService.getEmployeeByUserId(((MyUserDetails) event.getAuthentication().getPrincipal()).getUserId());
}
}
Is this a right way? Please suggest if there is a better way to handle shared data
Edit
Some background - I require the current logged in employee and a category which is common for all employees. So I autowired employeeService and categoryService in my controllers and use them to get the data. They are required in almost all my controller methods, so, I wanted to create a bean of these so that I directly use them in my controller and also save frequent database calls.
Normally, we only put the dependencies related to the cross-cutting concerns (i.e dependencies that are across the whole application such as security , logging , transaction stuff , time provider etc.) in the static field.
By accessing these kind of dependencies in the static way , we don't need to pass them through method parameters /constructors from object to object , which will make the API much cleaner without such noise (BTW. This is called Ambient Context Pattern in the .NET world).
Your Employee object most probably belong to this type , so it is ok to access it in a static way. But as their scope is per session , you cannot simply put it in the static field of a class. If yes, then you always get the same employee for all sessions. Instead, you have to somehow store it in an object which is session scope (e.g HttpSession) . Then at the beginning of handling a web request , you get it from the session and then put it in a ThreadLocal which is encapsulated inside a "ContextHolder" object. You then access that "ContextHolder" in a static way.
Sound very complicated and scary ? Don't worry as Spring Security has already implemented this stuff for you. What you need to do is to customize Authentication#getPrincipal()or extend default Authentication to contain your Employee. Then get it using SecurityContextHolder.getContext().getAuthentication()
For your currentCategory , if they are not the cross-cutting concerns and is the application scope , make a singleton bean to get it values is a much better OOP design.
#Component
public final class CurrentCategoryProvider {
#Autowired
private CategoryService categoryService;
public Category getCurrentCategory(){
//or cache the value to the an internal properties depending on your requirements
return categoryService.getCategory();
}
}
You then inject CurrentCategoryProvider to the bean that need to access currentCategory.
I've written a custom Validation Annotation and a ConstraintValidator implementation, which uses a Spring Service (and executes a Database Query):
public class MyValidator implements ConstraintValidator<MyValidationAnnotation, String> {
private final MyService service;
public MyValidator(MyService service) {
this.service = service;
}
#Override
public void initialize(MyValidationAnnotation constraintAnnotation) {}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return service.exists(value);
}
}
It's used like this:
public class MyEntity {
#Valid
List<Foo> list;
}
public class Foo {
#MyValidationAnnotation
String id;
}
This works quite nice, but service.exists(value) is getting called for every item within the list, which is correct, but could/should be optimized.
Question:
When validating an instance of MyEntity, I'd like to cache the results of the service.exists(value) calls.
I don't want to use a static HashMap<String, Boolean>, because this would cache the results for the entire application lifetime.
Is it possible to access some kind of Constraint Validation Context, which only exists while this particular validation is running, so I can put there the cached results?
Or do you have some other solution?
Thanks in advance!
You can use Spring's cache support. There might be other parts in the application which needs caching and this can be reused. And the setup is very simple too. And it will keep your code neat and readable.
You can cache your service calls. You need to put annotation on your service methods and a little bit of configuration.
And for cache provider you can use Ehcache. You have many options like setting ttl and max number of elements that can be cached and eviction policy etc etc if needed.
Or you can implement your own cache provider if your needs are simple. And if it is web request, In this cache you may find ThreadLocal to be useful. you can do all caching for this running thread using threadlocal. When the request is processed you can clear the threadlocal cache.
UPD 1: Upon further research I think the following information may be useful:
I obtain datasource through JNDI lookup on WildFly 9.0.2, then 'wrap' it into in instance of HikariDataSource (e. g. return new HikariDataSource(jndiDSLookup(dsName))).
the transaction manager that ends up being used is JTATransactionManager.
I do not configure the transaction manager in any way.
ORIGINAL QUESTION:
I am experiencing an issue with JPA/Hibernate and (maybe) Spring-Boot where DB changes introduced in a transactional method of one class called from a transactional method of another class are committed even though the changes in the caller method are rolled back (as they should be).
Here are my transactional services
StuffService:
#Service
#Transactional(rollbackFor = IOException.class)
public class StuffService {
#Inject private BarService barService;
#Inject private StuffRepository stuffRepository;
public Stuff updateStuff(Stuff stuff) {
try {
if (null != barService.doBar(stuff)) {
stuff.setSomething(SOMETHING);
stuff.setSomethingElse(SOMETHING_ELSE);
return stuffRepository.save(stuff);
}
} catch (FirstCustomException e) {
logger.error("Blah", e);
throw new SecondCustomException(e.getMessage());
}
throw new SecondCustomException("Blah 2");
}
// other methods
}
and BarService:
#Service
#Transactional
public class BarService {
#Inject private EntityARepository entityARepository;
#Inject private EntityBRepository entityBRepository;
/*
* updates existing entity A and persists new entity B.
*/
public EntityA doBar(Stuff stuff) throws FirstCustomException {
EntityA a = entityARepository.findOne(/* some criteria */);
a.setSomething(SOMETHING);
EntityB b = new EntityB();
b.setSomething(SOMETHING);
b.setSomethingElse(SOMETHING_ELSE);
entityBRepository.save(b);
return entityARepository.save(a);
}
// other methods
}
EntityARepository and EntityBRepository are very similar Spring-Boot repositories defined like this:
public interface EntityARepository extends JpaRepository<EntityA, Long>{
EntityA findOne(/* some criteria */);
}
FirstCustomException extends Throwable
SecondCustomException extends RuntimeException
Stuff entity is versioned, and every once in a while it is concurrently updated by StuffService.updateStuff(). In that case changes to one of the stuff instances are rolled back, as expected, but everything that happens in the barService.doBar() ends up being committed.
This puzzles me quite a lot since transaction propagation on both methods should be REQUIRED (the default one) and both methods belong to different classes, hence #Transactional should apply for both.
I did see Transaction is not completely rolled back after server throws OptimisticLockException1
But it did not really answer my question.
Can anyone please give me an idea of what's going on?
Thank you.
This isn't a 'nested' transaction - these services are operating in completely independent transactions. If you want the rollback of one to affect the other, you need to have them take part in the same transaction rather than start its own.
Or if your issue is that there is a problem with the version of 'stuff' passed into the doBar method and you want it verified, you will need to do something with the stuff instance that would cause an optimistic lock check, and so result in an exception if it is stale. see EntityManager.lock
I am reading through head first JSP and servlets. Going through different type of listeners, I came across HttpSessionBindingListener and HttpSessionAttributeListener.
I was thinking about the difference between the two - I want to see the practical usages in real world examples of those two listeners. I tested HttpSessionBindingListener by implementing valueBound() and valueUnBound() - why would an object need to know whether it has been added or not?
I am pretty confused about the practical usages. Please help in clarifying this.
The HttpSessionBindingListener is to be implemented on the class whose instances may be stored in the session, such as the logged-in user.
E.g.
public class ActiveUser implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
logins.add(this);
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
logins.remove(this);
}
}
When an instance of this ActiveUser get set as a session attribute by HttpSession#setAttribute(), then the valueBound() will be invoked. When it get removed by either HttpSession#removeAttribute(), or an invalidate of the session, or get replaced by another HttpSession#setAttribute(), then the valueUnbound() will be invoked.
Here are some real world use cases:
Getting SessionScoped bean from HttpSessionListener?
How to call a method before the session object is destroyed?
Call an action when closing a JSP
implementing HttpSessionListener
How to access HTTP sessions in Java
The HttpSessionAttributeListener is to be implemented as an application wide #WebListener which get invoked when any attribute is added, removed or replaced in the HttpSession. Continuing with the above ActiveUser example, this is particularly useful if you can't modify the ActiveUser class to implement HttpSessionBindingListener (because it's 3rd party or so), or when you want to make use of a "marker interface" on an arbitrary amount of classes so that you can do the listening job in a single central place.
#WebListener
public class ActiveUserListener implements HttpSessionAttributeListener {
#Override
public void attributeAdded(HttpSessionBindingEvent event) {
if (event.getValue() instanceof ActiveUser) {
logins.add(event.getValue());
}
}
#Override
public void attributeRemoved(HttpSessionBindingEvent event) {
if (event.getValue() instanceof ActiveUser) {
logins.remove(event.getValue());
}
}
#Override
public void attributeReplaced(HttpSessionBindingEvent event) {
if (event.getValue() instanceof ActiveUser) {
logins.add(event.getValue());
}
}
}
Here's a real world use case:
Getting notification when bounded/unbounded to a HTTP session
I'm using the Wicket Auth/Roles and I ran into the same problem as the OP of this thread.
I need to access the DB service layer in the AuthenticatedWebSession (for user authentication). I followed Steve Flasby's suggestion and did the following:
#Override
public Session newSession(Request request, Response response) {
Session s = new MySession(request);
mInjector.inject(s);
return s;
}
Unfortunately this results in
java.lang.IllegalStateException: EntityManager is closed
(presumably due to the fact that (a) I'm using open session in view, and (b) the session spans over several requests).
I solved this by moving the injection into the AuthenticatedWebSession.authenticate method.
#Override
public boolean authenticate(String username, String pass) {
Injector.get().inject(this);
...
}
I suspect that this is not best practice, because now I need to access to the service layer in other methods too, and it doesn't seem like a good idea to add Injector.get().inject(this) in each such method.
My question:
How do I perform injection into the session object upon each request? (Or, if this is a bad approach all together, how do I access the service layer in the AuthenticatedWebSession?)
You can implement IRequestCycleListener (extend AbstractRequestCycleListener) and implement:
#Override
public void onBeginRequest(RequestCycle cycle)
{
if (Session.exists()) {
Injector.get().inject(Session.get());
}
}
Register your IRequestCycleListener in Application#init() with getRequestCycleListeners().add(new YourRequestCycleListener()).